
bl_info = {
    "name": "IMVU Studio Toolkit",
    "author": "IMVU Inc.",
    "version": (1, 1, 4),
    "blender": (3, 3, 21),
    "location": "View3D > IMVU Studio Toolkit",
    "description": "Easily create base meshes to work from",
    "warning": "",
    "doc_url": "https://create.imvu.com/articles/studio/toolkit/#blender",
    "category": "IMVU",
}

import bpy
import math
import os
import platform
import requests
import json
import re
import subprocess

needUpdate = False
isDevVersion = False
isAligned = False
oldAnimLen = 50
errorStr = ""

def GetPathToFile(self, fileName):
    addonsDir = bpy.utils.user_resource('SCRIPTS', path="addons")
    filePath = None
    for dirpath, subdirs, files in os.walk(addonsDir):
        if filePath:
            break
        for file in files:
            if file == fileName:
               filePath = os.path.join(dirpath, file)
               break
    if not filePath:
       self.report({"WARNING"}, "FILE NOT FOUND! : " + fileName)
    return filePath

def CheckUpdate():
    global needUpdate
    global isDevVersion

    needUpdate = False
    isDevVersion = False

    localVersion = str(list(bl_info.get("version"))[0]) + "." + str(list(bl_info.get("version"))[1]) + "." + str(list(bl_info.get("version"))[2])
    onlineVersion = "UNKNOWN"
    headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
    response = requests.get("https://create.imvu.com/api/studio/blender", headers=headers);
    #response = requests.get("https://create.imvu.com/api/studio/blender", headers={}); #DEBUG-TEST
    
    if str(response) != "<Response [200]>":
        print ("IMVU Studio Toolkit failed to retrieve current version from server! " + str(response))
    else:
        body = json.loads(response.text)
        onlineVersion = (body['data']['version'])
        if onlineVersion > localVersion:
            needUpdate = True
        elif onlineVersion < localVersion:
            isDevVersion = True

    print ("Online Version: " + str(onlineVersion))
    print ("Local Version: " + str(localVersion))

CheckUpdate()

def ScaleCube(self, context, xyz):
    scene = context.scene
    imvutool = scene.imvu_tool

    DelInitialCollection()

    isCube = False
    isRoom = False
    isRefCol = False

    for o in bpy.context.scene.objects:
        if o.name == "Room_Reference":
            isCube = True
        if o.name == "Room_Ref":
            isRoom = True
            
    for col in bpy.data.collections:
        if col.name == "REFERENCE":
            isRefCol = True

    if not isCube and not isRoom: 
        for area in bpy.context.screen.areas: 
            if area.type == 'VIEW_3D':
                for space in area.spaces: 
                    if space.type == 'VIEW_3D':
                        space.shading.type = 'MATERIAL'

        if isRefCol:
            self.layer_collection = bpy.data.collections["REFERENCE"]
            bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(0, 0, 20), scale=(40, 40, 40))
            roomMesh = bpy.context.selected_objects[0]
            bpy.ops.collection.objects_remove_all()
            bpy.data.collections['REFERENCE'].objects.link(roomMesh)
            roomMesh.name = "Room_Ref"
            ob = bpy.context.scene.objects["Room_Ref"]
            bpy.context.view_layer.objects.active = ob
            ob.select_set(True)
            bpy.ops.object.mode_set(mode= 'OBJECT')
            bpy.ops.object.select_all(action='DESELECT')
            bpy.data.objects["Room_Ref"].select_set(True)
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.uv.smart_project()
            mat = bpy.data.materials.get("M_Room")
            roomMesh.data.materials.append(mat)

            xVal = bpy.context.object.dimensions[0]
            yVal = bpy.context.object.dimensions[1]
            zVal = bpy.context.object.dimensions[2]
            bpy.ops.object.mode_set(mode= 'EDIT')
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.transform.resize(value=(imvutool.room_size_x/xVal, imvutool.room_size_y/yVal, imvutool.room_size_z/zVal))
            bpy.context.object.location[2] = imvutool.room_size_z / 2

            for area in bpy.context.screen.areas: 
                if area.type == 'VIEW_3D':
                    for space in area.spaces: 
                        if space.type == 'VIEW_3D':
                            space.shading.type = 'MATERIAL'
            
            ob = bpy.context.scene.objects["Room_Ref"]
            bpy.context.view_layer.objects.active = ob
            ob.select_set(True)
            bpy.ops.object.mode_set(mode= 'EDIT')
            bpy.ops.mesh.flip_normals()
            bpy.ops.object.mode_set(mode= 'OBJECT')
        else:
            bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(0, 0, 20), scale=(40, 40, 40))
            refRoom = bpy.context.selected_objects[0]
            refRoom.name = "Room_Reference" 

            ob = bpy.context.scene.objects["Room_Reference"]
            bpy.context.view_layer.objects.active = ob
            ob.select_set(True)

            xVal = bpy.context.object.dimensions[0]
            yVal = bpy.context.object.dimensions[1]
            zVal = bpy.context.object.dimensions[2]
            bpy.ops.object.mode_set(mode= 'EDIT')
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.transform.resize(value=(imvutool.room_size_x/xVal, imvutool.room_size_y/yVal, imvutool.room_size_z/zVal))
            bpy.context.object.location[2] = imvutool.room_size_z / 2


    if not isRoom and not isRefCol:
        ob = bpy.context.scene.objects["Room_Reference"]
        bpy.context.view_layer.objects.active = ob
        ob.select_set(True)
    

        if (xyz == "X") or (xyz == "Y") or (xyz == "Z"):
            xVal = bpy.context.object.dimensions[0]
            yVal = bpy.context.object.dimensions[1]
            zVal = bpy.context.object.dimensions[2]
            bpy.ops.object.mode_set(mode= 'EDIT')
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.transform.resize(value=(imvutool.room_size_x/xVal, imvutool.room_size_y/yVal, imvutool.room_size_z/zVal))
            bpy.context.object.location[2] = imvutool.room_size_z / 2
            

        bpy.ops.object.mode_set(mode= 'OBJECT') 
        

    if isRoom and not isCube:
        ob = bpy.context.scene.objects["Room_Ref"]
        bpy.context.view_layer.objects.active = ob
        ob.select_set(True)
    

        if (xyz == "X") or (xyz == "Y") or (xyz == "Z"):
            xVal = bpy.context.object.dimensions[0]
            yVal = bpy.context.object.dimensions[1]
            zVal = bpy.context.object.dimensions[2]
            bpy.ops.object.mode_set(mode= 'EDIT')
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.transform.resize(value=(imvutool.room_size_x/xVal, imvutool.room_size_y/yVal, imvutool.room_size_z/zVal))
            bpy.context.object.location[2] = imvutool.room_size_z / 2
            

        bpy.ops.object.mode_set(mode= 'OBJECT')

def AnimLength(self, context):
    scene = context.scene
    imvutool = scene.imvu_tool

    bpy.context.scene.frame_end = imvutool.animationLen

def PoseLen(self, context):
    global oldAnimLen

    scene = context.scene
    imvutool = scene.imvu_tool

    if (imvutool.isPose):
        oldAnimLen = imvutool.animationLen
        imvutool.animationLen = 10
    else:
        imvutool.animationLen = oldAnimLen

def AddSeat(self, context, seatType, ifCall_H, ifCall_CP, collection):
    
    scene = context.scene
    imvutool = scene.imvu_tool
    self.master_collection = bpy.context.scene.collection
    self.layer_collection = bpy.data.collections[collection] #Set collection
    scene_collection = bpy.context.view_layer.layer_collection
    bpy.context.view_layer.active_layer_collection = scene_collection

    bpy.ops.object.mode_set(mode= 'OBJECT')

    numSeats = 1
    SeatNum = str(numSeats).zfill(2)

    newList = []

    for each in self.layer_collection.objects:
        newList.append(str(each))

    for o in sorted(newList):
        if "Seat" + str(numSeats).zfill(2) in o:
            numSeats += 1
            
        seat_str = str(numSeats)
        SeatNum = seat_str.zfill(2)

    #Seatxx_Sitting
    bpy.ops.ed.undo_push()
    bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
    seat = bpy.context.selected_objects[0]
    seat.name = "Seat" + SeatNum + "." + seatType
    bpy.context.object.empty_display_size = 1
    bpy.context.object.show_name = True
    bpy.context.object.show_in_front = True
    self.layer_collection.objects.link(context.object) #Link with collection
    self.master_collection.objects.unlink(context.object) #Unlink from master collection
    seat.parent = bpy.data.objects['AvatarNodes']
    
    if ifCall_H:
        #Handlexx
        bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 5), scale=(1, 1, 1))
        seatHandle = bpy.context.selected_objects[0]
        seatHandle.name = "Handle" + SeatNum
        bpy.context.object.empty_display_size = 1
        bpy.context.object.show_name = True
        bpy.context.object.show_in_front = True
        self.layer_collection.objects.link(context.object) #Link with collection
        self.master_collection.objects.unlink(context.object) #Unlink from master collection
        seatHandle.parent = seat
    if ifCall_CP:
        #Catcherxx_Sitting
        bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, -3, 0), scale=(1, 1, 1))
        seatCatch = bpy.context.selected_objects[0]
        seatCatch.name = "Catcher" + SeatNum + "." + seatType
        bpy.context.object.empty_display_size = .75
        bpy.context.object.show_name = True
        bpy.context.object.show_in_front = True
        self.layer_collection.objects.link(context.object) #Link with collection
        self.master_collection.objects.unlink(context.object) #Unlink from master collection
        seatCatch.parent = seat
        #Pitcherxx_Sitting
        bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, -5, 0), scale=(1, 1, 1), rotation= (0, 0, math.radians(180)))
        seatPitch = bpy.context.selected_objects[0]
        seatPitch.name = "Pitcher" + SeatNum + "." + seatType
        bpy.context.object.empty_display_size = .75
        bpy.context.object.show_name = True
        bpy.context.object.show_in_front = True
        self.layer_collection.objects.link(context.object) #Link with collection
        self.master_collection.objects.unlink(context.object) #Unlink from master collection
        seatPitch.parent = seatCatch

    bpy.ops.object.select_all(action='DESELECT')
    objToSelect = bpy.data.objects[seat.name]
    objToSelect.select_set(True)
    bpy.context.view_layer.objects.active = objToSelect
        
def ChangeIK(self, context):
    scene = context.scene
    imvutool = scene.imvu_tool
    for bone in bpy.context.object.pose.bones:
        if "CTRL_COG" in bone.name:
            bpy.ops.object.mode_set(mode='POSE') 
            bone["FK > IK Arm.L"] = int(imvutool.leftArmIK == True)
            bone["FK > IK Arm.R"] = int(imvutool.rightArmIK == True)
            bone["FK > IK Leg.L"] = int(imvutool.leftLegIK == True)
            bone["FK > IK Leg.R"] = int(imvutool.rightLegIK == True)

            bone["IsoRot_ArmFK_L"] = int(imvutool.leftArmIso == False)
            bone["IsoRot_ArmFK_R"] = int(imvutool.rightArmIso == False)
            bone["IsoRot_LegFK_L"] = int(imvutool.leftLegIso == False)
            bone["IsoRot_LegFK_R"] = int(imvutool.rightLegIso == False)

            for rig in bpy.data.objects:
                if "Control_Armature" in rig.name:
                    rig.data.bones["CTRL_FemaleRoot"].select = True
    
def AddNode(self, context, nodeType, collection):
    scene = context.scene
    imvutool = scene.imvu_tool
    self.master_collection = bpy.context.scene.collection
    self.layer_collection = bpy.data.collections[collection] #Set collection
    
    scene_collection = bpy.context.view_layer.layer_collection
    bpy.context.view_layer.active_layer_collection = scene_collection

    obj = bpy.context.selected_objects
    bpy.ops.object.mode_set(mode= 'OBJECT')
    bpy.ops.object.select_all(action='DESELECT')

    for eachSeat in range(len(obj)):
        if "Seat" in obj[eachSeat].name:
            bpy.data.objects[obj[eachSeat].name].select_set(True)

    seatSelection = bpy.context.selected_objects
    for eachSeat in range(len(bpy.context.selected_objects)):
        SeatNum = obj[eachSeat].name.split(".",1)[0][4:]
        seatType = obj[eachSeat].name.split(".",1)[1]
        if nodeType == "Add Catch":
            isCatch = False
            for each in obj[eachSeat].children:
                if "Catcher" in each.name:
                    isCatch = True
            if not isCatch:
                #Catcher
                bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, -3, 0), scale=(1, 1, 1))
                seatCatch = bpy.context.selected_objects[0]
                seatCatch.name = "Catcher" + SeatNum + "." + seatType
                bpy.context.object.empty_display_size = .75
                bpy.context.object.show_name = True
                bpy.context.object.show_in_front = True
                self.layer_collection.objects.link(context.object) #Link with collection
                self.master_collection.objects.unlink(context.object) #Unlink from master collection
                seatCatch.parent = obj[eachSeat]
                #Pitcher
                bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, -5, 0), scale=(1, 1, 1), rotation= (0, 0, math.radians(180)))
                seatPitch = bpy.context.selected_objects[0]
                seatPitch.name = "Pitcher" + SeatNum + "." + seatType
                bpy.context.object.empty_display_size = .75
                bpy.context.object.show_name = True
                bpy.context.object.show_in_front = True
                self.layer_collection.objects.link(context.object) #Link with collection
                self.master_collection.objects.unlink(context.object) #Unlink from master collection
                seatPitch.parent = seatCatch

                bpy.ops.object.select_all(action='DESELECT')
                bpy.data.objects[obj[eachSeat].name].select_set(True)




        if nodeType == "Del Catch":
            isCatch = False
            for each in obj[eachSeat].children:
                if "Catcher" in each.name:
                    isCatch = True
            if isCatch:
                for each in obj[eachSeat].children:
                    if "Catcher" in each.name:
                        if obj[eachSeat].children[0].children[0].name == ("Pitcher" + SeatNum + "." + seatType):
                            bpy.ops.object.select_all(action='DESELECT')
                            obj[eachSeat].children[0].children[0].select_set(True)
                            bpy.ops.object.delete()
                        if obj[eachSeat].children[0].name == ("Catcher" + SeatNum + "." + seatType):
                            bpy.ops.object.select_all(action='DESELECT')
                            obj[eachSeat].children[0].select_set(True)
                            bpy.ops.object.delete()
                        

            bpy.ops.object.select_all(action='DESELECT')
            bpy.data.objects[obj[eachSeat].name].select_set(True)

        if nodeType == "Add Handle":
            isHandle = False
            for each in obj[eachSeat].children:
                if "Handle" in each.name:
                    isHandle = True
            if not isHandle:
                #Handle
                bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 5), scale=(1, 1, 1))
                seatHandle = bpy.context.selected_objects[0]
                seatHandle.name = "Handle" + SeatNum
                bpy.context.object.empty_display_size = 1
                bpy.context.object.show_name = True
                bpy.context.object.show_in_front = True
                self.layer_collection.objects.link(context.object) #Link with collection
                self.master_collection.objects.unlink(context.object) #Unlink from master collection
                seatHandle.parent = obj[eachSeat]
                
                bpy.ops.object.select_all(action='DESELECT')
                bpy.data.objects[obj[eachSeat].name].select_set(True)

        if nodeType == "Del Handle":
            isHandle = False
            for each in obj[eachSeat].children:
                if "Handle" in each.name:
                    isHandle = True
            if isHandle:
                for each in obj[eachSeat].children:
                    if "Handle" in each.name:
                        bpy.ops.object.select_all(action='DESELECT')
                        each.select_set(True)
                        bpy.ops.object.delete()

    bpy.ops.object.select_all(action='DESELECT')
    for oldSel in range(len(seatSelection)):
        # bpy.data.objects[seatSelection[oldSel].name].select_set(True)
    
        objectToSelect = bpy.data.objects[seatSelection[oldSel].name]
        objectToSelect.select_set(True)    
        bpy.context.view_layer.objects.active = objectToSelect

def atoi(text):
    return int(text) if text.isdigit() else text

def natural_keys(text):
    return [ atoi(c) for c in re.split('(\d+)',text) ]

def DuplicateNode(self, context, direction, space, myScene):
    scene = context.scene
    imvutool = scene.imvu_tool
    self.master_collection = bpy.context.scene.collection
    
    scene_collection = bpy.context.view_layer.layer_collection
    bpy.context.view_layer.active_layer_collection = scene_collection

    obj = bpy.context.selected_objects
    x_amount = 0
    y_amount = 0
    z_amount = 0

    bpy.context.scene.transform_orientation_slots[0].type = 'LOCAL'

    if direction == "N":
        y_amount = space
    if direction == "S":
        y_amount = -space
    if direction == "E":
        x_amount = space
    if direction == "W":
        x_amount = -space

    
    for sel in bpy.context.selected_objects:
        if "Ceiling" in sel.name:
            x_amount = -x_amount

    isSeat = False
    isFurn = False

    if (not ("Seat" in obj[0].name)) and (not ("furniture." in obj[0].name)):
        self.report({"WARNING"}, "Please select a seat or furniture node!")

    if "Seat" in obj[0].name:
        isSeat = True
    if "furniture." in obj[0].name:
        isFurn = True

    if isSeat:
        self.layer_collection = bpy.data.collections[myScene] #Set collection
        
        bpy.ops.object.duplicate()
        bpy.ops.transform.translate(value=(x_amount, y_amount, z_amount))
        for eachSeat in range(len(bpy.context.selected_objects)):
            isCatch = False
            isHandle = False
            seatType = ""
            for each in obj[eachSeat].children:
                if "Catcher" in each.name:
                    isCatch = True
                if "Handle" in each.name:
                    isHandle = True
            seatType = obj[eachSeat].name.split(".",1)[1]

            newSeat = bpy.context.selected_objects
            numSeats = 1
            SeatNum = str(numSeats).zfill(2)
            
            newList = []

            for each in self.layer_collection.objects:
                newList.append(str(each))

            newList.sort(key=natural_keys)

            for o in newList:
                if "Seat" + str(numSeats).zfill(2) in o:
                    numSeats += 1
                seat_str = str(numSeats)
                SeatNum = seat_str.zfill(2) 

            newName = "Seat" + SeatNum + "." + seatType
            newSeat[eachSeat].name = newName
            # self.report({"WARNING"}, newName)
        if isCatch:
            AddNode(self, context, "Add Catch", myScene)
        if isHandle:
            AddNode(self, context, "Add Handle", myScene)
                

    if isFurn:
        self.layer_collection = bpy.data.collections[myScene] #Set collection
        bpy.ops.object.duplicate()
        newFurn = bpy.context.selected_objects
        for x in range(len(newFurn)):
            newFurn[x].name = "Temp" + str(x)
        bpy.ops.transform.translate(value=(x_amount, y_amount, z_amount))
        furnType = ""

        if "Wall" in obj[0].name:
            furnType = "Wall."
            for x in range(len(newFurn)):
                numWalls = 1

                wallList = []

                for each in self.layer_collection.objects:
                    wallList.append(str(each))

                wallList.sort(key=natural_keys)

                for o in wallList:
                    if "Wall." + str(numWalls).zfill(2) in o:
                        numWalls += 1
                        
                    seat_str = str(numWalls)
                    wallNum = seat_str.zfill(2)

                newName = "furniture." + furnType + wallNum
                newFurn[x].name = newName

        if "Floor" in obj[0].name:
            furnType = "Floor."
            for x in range(len(newFurn)):
                numFloors = 1

                floorList = []

                for each in self.layer_collection.objects:
                    floorList.append(str(each))

                floorList.sort(key=natural_keys)

                for o in floorList:
                    if "Floor." + str(numFloors).zfill(2) in o:
                        numFloors += 1
                        
                    seat_str = str(numFloors)
                    floorNum = seat_str.zfill(2)

                newName = "furniture." + furnType + floorNum
                newFurn[x].name = newName

        if "Ceiling" in obj[0].name:
            furnType = "Ceiling."
            for x in range(len(newFurn)):
                numCeilings = 1

                ceilingList = []

                for each in self.layer_collection.objects:
                    ceilingList.append(str(each))

                ceilingList.sort(key=natural_keys)

                for o in ceilingList:
                    if "Ceiling." + str(numCeilings).zfill(2) in o:
                        numCeilings += 1
                        
                    seat_str = str(numCeilings)
                    ceilingNum = seat_str.zfill(2)

                newName = "furniture." + furnType + ceilingNum
                newFurn[x].name = newName

def CreateSeeThrough(self, context, collection, parent):
    self.master_collection = bpy.context.scene.collection
    self.layer_collection = bpy.data.collections[collection]
    context.view_layer.active_layer_collection = context.view_layer.layer_collection

    bpy.ops.ed.undo_push()
    numSeeThrough = 1
    for collections in bpy.data.collections:
        if (collections.name == collection):
            for obj in bpy.data.collections[collection].all_objects:
                if "SeeThroughArmature" in obj.name:
                    numSeeThrough += 1

    if (numSeeThrough == 1):
        proxyCone = bpy.ops.mesh.primitive_cone_add(radius1=1, radius2=0, depth=2, enter_editmode=False, align='WORLD', location=(0, -1, 0), scale=(1, 1, 1), rotation= ((math.pi * 90 / 180),0,0))
        bpy.ops.object.transform_apply(location=True, rotation=False, scale=False)
        for obj in bpy.context.selected_objects:
            obj.name = "ProxyCone"
            obj.hide_viewport = True

    bpy.ops.object.armature_add(enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
    STArm = bpy.context.selected_objects[0]

    for obj in bpy.context.selected_objects:
        obj.name = ("SeeThroughArmature" + str(numSeeThrough).zfill(2))
    for b in bpy.context.object.data.bones:
        b.name = ("SeeThrough" + str(numSeeThrough).zfill(2))
        bpy.context.object.pose.bones["SeeThrough" + str(numSeeThrough).zfill(2)].custom_shape = bpy.data.objects["ProxyCone"]

    self.layer_collection.objects.link(context.object) #Link with collection
    self.master_collection.objects.unlink(context.object) #Unlink from master collection

    STArm.parent = bpy.data.objects[parent]

def LinkSeeThrough(self):
    verts = []
    obj = bpy.context.selected_objects

    isArmature = False
    isMesh = False
    numArmature = 0

    if len(obj) == 0:
        self.report({"WARNING"}, "Please select an object to attach!")
    else:
        for obj in range(len(bpy.context.selected_objects)):
            if "SeeThroughArmature" in bpy.context.selected_objects[obj].name:
                STArmature = bpy.context.selected_objects[obj]
                isArmature = True
                seeThroughNum = str(bpy.context.selected_objects[obj].name)[-2:]
                numArmature += 1
            if bpy.context.selected_objects[obj].type == "MESH":
                isMesh = True

        if numArmature > 1:
            self.report({"WARNING"}, "Please select only one SeeThrough node!")
        if isArmature and not isMesh:
            self.report({"WARNING"}, "Please select an object to attach!")
        if isMesh and not isArmature:
            self.report({"WARNING"}, "Please select an armature to attach!")
        if isArmature and isMesh:
            bpy.data.objects[STArmature.name].select_set(False)
            for each in range(0, len(bpy.context.selected_objects)):
                STObj = bpy.context.selected_objects[each]
                bpy.ops.object.mode_set(mode='OBJECT')
                if ".STMESH" not in STObj.name:
                    STObj.name = (str(STObj.name) + ".STMESH" + str(seeThroughNum))
                if not STObj.modifiers:
                    STObj.modifiers.new("Armature", type='ARMATURE')
                    STObj.modifiers["Armature"].object = bpy.data.objects["SeeThroughArmature" + str(seeThroughNum)]

                    group = STObj.vertex_groups.new(name=("SeeThrough" + str(seeThroughNum)))

                    for vert in range(len(STObj.data.vertices)):
                        verts.append(vert)
                    group.add( verts, 1, 'REPLACE' )
                    STObj.parent = STArmature
                    STObj.matrix_parent_inverse = STArmature.matrix_world.inverted()
                else:
                    
                    STObj.modifiers.clear()
                    STObj.vertex_groups.clear()

                    STObj.modifiers.new("Armature", type='ARMATURE')
                    STObj.modifiers["Armature"].object = bpy.data.objects["SeeThroughArmature" + str(seeThroughNum)]

                    group = STObj.vertex_groups.new(name=("SeeThrough" + str(seeThroughNum)))

                    for vert in range(len(STObj.data.vertices)):
                        verts.append(vert)
                    group.add( verts, 1, 'REPLACE' )
                    STObj.parent = STArmature
                    STObj.matrix_parent_inverse = STArmature.matrix_world.inverted()

def UnlinkSeeThrough(self, parent):
        obj = bpy.context.selected_objects

        if len(obj) == 0:
            self.report({"WARNING"}, "Please select an object!")
        elif not obj[0].type == "MESH":
            self.report({"WARNING"}, "Please select a mesh!")
        else:
            for each in range(len(obj)):
                bpy.ops.object.mode_set(mode='OBJECT')
                obj[each].parent = bpy.data.objects[parent]
                if ".STMESH" in obj[each].name:
                    obj[each].name = str(obj[each].name)[:len(obj[each].name)-9]
                if obj[each].modifiers:
                    obj[each].modifiers.clear()
                    obj[each].vertex_groups.clear()

def DelInitialCollection():
    for col in bpy.context.view_layer.layer_collection.children:
                if col.name == "Collection":
                    col = bpy.data.collections.get('Collection')
                    bpy.data.collections.remove(col)

def checkMega():
    
    sceneCount = 0
    for col in bpy.context.view_layer.layer_collection.children:
        if col.name == "Attachment_Scene":
            sceneCount += 1
        if col.name == "Clothing_Scene":
            sceneCount += 1
        if col.name == "Animation_Scene":
            sceneCount += 1
            
    if (sceneCount > 1):
        return False
    return True

def setMaleFemaleAttachment(self, context):
    scene = context.scene
    imvutool = scene.imvu_tool
    
    maleMesh = bpy.data.collections.get("Attachment_Male_Mesh")
    femaleMesh = bpy.data.collections.get("Attachment_Female_Mesh")
    maleMesh_1_5 = bpy.data.collections.get("Attachment_Male_Mesh_1_5")
    femaleMesh_1_5 = bpy.data.collections.get("Attachment_Female_Mesh_1_5")

    if imvutool.attachment_gender == "Male":
        for obj in femaleMesh.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
        for obj in maleMesh_1_5.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
        for obj in femaleMesh_1_5.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
        for obj in maleMesh.objects:
            if(obj.hide_get() == True):
                obj.hide_set(False)
    if imvutool.attachment_gender == "Female":
        for obj in maleMesh.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
        for obj in maleMesh_1_5.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
        for obj in femaleMesh_1_5.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
        for obj in femaleMesh.objects:
            if(obj.hide_get() == True):
                obj.hide_set(False)
    if imvutool.attachment_gender == "Male 1.5":
        for obj in maleMesh_1_5.objects:
            if(obj.hide_get() == True):
                obj.hide_set(False)
        for obj in femaleMesh_1_5.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
        for obj in maleMesh.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
        for obj in femaleMesh.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
    if imvutool.attachment_gender == "Female 1.5":
        for obj in femaleMesh_1_5.objects:
            if(obj.hide_get() == True):
                obj.hide_set(False)
        for obj in maleMesh_1_5.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
        for obj in maleMesh.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
        for obj in femaleMesh.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
    if imvutool.attachment_gender == "Hide":
        for obj in maleMesh.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
        for obj in femaleMesh.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
        for obj in maleMesh_1_5.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)
        for obj in femaleMesh_1_5.objects:
            if(obj.hide_get() == False):
                obj.hide_set(True)

def setMaleFemaleHead(self, context):
    scene = context.scene
    imvutool = scene.imvu_tool

    if imvutool.head_gender == "Male":
        bpy.data.objects['MaleNeck'].hide_set(False)
        bpy.data.objects['FemaleNeck'].hide_set(True)
    if imvutool.head_gender == "Female":
        bpy.data.objects['FemaleNeck'].hide_set(False)
        bpy.data.objects['MaleNeck'].hide_set(True)

def hideAttachment():
    maleMesh = bpy.data.collections.get("Attachment_Male_Mesh")
    femaleMesh = bpy.data.collections.get("Attachment_Female_Mesh")
    maleMesh_1_5 = bpy.data.collections.get("Attachment_Male_Mesh_1_5")
    femaleMesh_1_5 = bpy.data.collections.get("Attachment_Female_Mesh_1_5")

    for obj in femaleMesh.objects:
        obj.hide_set(True)
    for obj in maleMesh.objects:
        obj.hide_set(True)
    for obj in femaleMesh_1_5.objects:
        obj.hide_set(True)
    for obj in maleMesh_1_5.objects:
        obj.hide_set(True)

def setMaleFemaleClothing(self, context):
    scene = context.scene
    imvutool = scene.imvu_tool
    
    maleMesh = bpy.data.collections.get("Clothing_Male_Mesh")
    femaleMesh = bpy.data.collections.get("Clothing_Female_Mesh")
    maleMesh_1_5 = bpy.data.collections.get("Clothing_Male_Mesh_1_5")
    femaleMesh_1_5 = bpy.data.collections.get("Clothing_Female_Mesh_1_5")
    maleMCG = bpy.data.collections.get("MCG_Male_Mesh")
    femaleMCG = bpy.data.collections.get("MCG_Female_Mesh")

    if imvutool.clothing_gender == "Male":
        for obj in femaleMesh.objects:
            obj.hide_set(True)
        for obj in maleMesh_1_5.objects:
            obj.hide_set(True)
        for obj in femaleMesh_1_5.objects:
            obj.hide_set(True)
        for obj in maleMesh.objects:
            obj.hide_set(False)
        for obj in femaleMCG.objects:
            obj.hide_set(True)
        for obj in maleMCG.objects:
            obj.hide_set(not imvutool.showMCG)
    if imvutool.clothing_gender == "Female":
        for obj in maleMesh.objects:
            obj.hide_set(True)
        for obj in maleMesh_1_5.objects:
            obj.hide_set(True)
        for obj in femaleMesh_1_5.objects:
            obj.hide_set(True)
        for obj in femaleMesh.objects:
            obj.hide_set(False)
        for obj in femaleMCG.objects:
            obj.hide_set(not imvutool.showMCG)
        for obj in maleMCG.objects:
            obj.hide_set(True)
    if imvutool.clothing_gender == "Male 1.5":
        for obj in maleMesh_1_5.objects:
            obj.hide_set(False)
        for obj in femaleMesh_1_5.objects:
            obj.hide_set(True)
        for obj in maleMesh.objects:
            obj.hide_set(True)
        for obj in femaleMesh.objects:
            obj.hide_set(True)
        for obj in femaleMCG.objects:
            obj.hide_set(True)
        for obj in maleMCG.objects:
            obj.hide_set(not imvutool.showMCG)
    if imvutool.clothing_gender == "Female 1.5":
        for obj in femaleMesh_1_5.objects:
            obj.hide_set(False)
        for obj in maleMesh_1_5.objects:
            obj.hide_set(True)
        for obj in maleMesh.objects:
            obj.hide_set(True)
        for obj in femaleMesh.objects:
            obj.hide_set(True)
        for obj in femaleMCG.objects:
            obj.hide_set(not imvutool.showMCG)
        for obj in maleMCG.objects:
            obj.hide_set(True)
    if imvutool.clothing_gender == "Hide":
        for obj in maleMesh.objects:
            obj.hide_set(True)
        for obj in femaleMesh.objects:
            obj.hide_set(True)
        for obj in maleMesh_1_5.objects:
            obj.hide_set(True)
        for obj in femaleMesh_1_5.objects:
            obj.hide_set(True)
        for obj in femaleMCG.objects:
            obj.hide_set(True)
        for obj in maleMCG.objects:
            obj.hide_set(True)

def ShowHideMorph(self, context):
    scene = context.scene
    imvutool = scene.imvu_tool
    
    bpy.context.view_layer.objects.active = bpy.data.objects["Anim"]
    bpy.ops.object.mode_set(mode= 'OBJECT')
    bpy.ops.object.select_all(action='DESELECT')

    for each in bpy.data.collections:
        if "BlendControls" in each.name:
            blendControls = each
            for obj in blendControls.objects:
                obj.hide_set(not imvutool.enableMorph)
    
    for each in bpy.data.objects:
        if "Control_Armature" in each.name:
            each.select_set(True)
            each.data.layers[7] = imvutool.enableMorph

    bpy.ops.object.select_all(action='DESELECT')
    
def ShowHideMCG(self, context):
    scene = context.scene
    imvutool = scene.imvu_tool
    
    if not imvutool.showMCG:
        for each in bpy.data.collections:
            if "MCG" in each.name:
                MCGCol = each
                for obj in MCGCol.objects:
                    obj.hide_set(not imvutool.showMCG)
    else:
        for each in bpy.data.collections:
            if "MCG" in each.name and imvutool.clothing_gender[:4] in each.name:
                MCGCol = each
                for obj in MCGCol.objects:
                    obj.hide_set(not imvutool.showMCG)

def ScaleMCG(self, context):
    scene = context.scene
    imvutool = scene.imvu_tool

    bpy.data.shape_keys["FemaleKey"].key_blocks["MCG_Female_Large"].value = imvutool.MCGSlider
    bpy.data.shape_keys["MaleKey"].key_blocks["MCG_Male_Large"].value = imvutool.MCGSlider
    bpy.data.shape_keys["BreastKey"].key_blocks["F_Guide_Breast_Bot_Large"].value = imvutool.MCGSlider



class MyProperties(bpy.types.PropertyGroup):

    room_size_x :bpy.props.FloatProperty(
        name= "X",
        description= "Width",
        default= 40,
        soft_min= 1,
        soft_max= 100,
        update= lambda s, c: ScaleCube(s, c, 'X')
    )
    room_size_y :bpy.props.FloatProperty(
        name= "Y",
        description= "Depth",
        default= 40,
        soft_min= 1,
        soft_max= 100,
        update= lambda s, c: ScaleCube(s, c, 'Y')
    )
    room_size_z :bpy.props.FloatProperty(
        name= "Z",
        description= "Height",
        default= 40,
        soft_min= 1,
        soft_max= 100,
        update= lambda s, c: ScaleCube(s, c, 'Z')
    )
    animationLen :bpy.props.IntProperty(
        name= "Animation Length",
        description= "How long your animation is in frames",
        default= 50,
        update= lambda s, c: AnimLength(s, c)
    )

    clothing_gender :bpy.props.EnumProperty(
        items=[
            ('Male', 'Male', 'Set Mesh to Male', '', 0),
            ('Female', 'Female', 'Set Mesh to Female', '', 1),
            ('Male 1.5', 'Male 1.5', 'Set Mesh to High-Res Male \n\n1.5 meshes should be used as a smoother alternative when making clothing that shows body parts. \nYou should not reference this mesh for shape accuracy', '', 2),
            ('Female 1.5', 'Female 1.5', 'Set Mesh to High-Res Female \n\n1.5 meshes should be used as a smoother alternative when making clothing that shows body parts. \nYou should not reference this mesh for shape accuracy', '', 3),
            ('Hide', 'Hide', 'Hide Avatar Mesh', '', 4)
        ],
        default='Male 1.5',
        update= lambda s, c: setMaleFemaleClothing(s, c)
    )
    attachment_gender :bpy.props.EnumProperty(
        items=[
            ('Male', 'Male', 'Set Mesh to Male', '', 0),
            ('Female', 'Female', 'Set Mesh to Female', '', 1),
            ('Male 1.5', 'Male 1.5', 'Set Mesh to High-Res Male \n\n1.5 meshes should be used as a smoother alternative when making clothing that shows body parts. \nYou should not reference this mesh for shape accuracy', '', 2),
            ('Female 1.5', 'Female 1.5', 'Set Mesh to High-Res Female \n\n1.5 meshes should be used as a smoother alternative when making clothing that shows body parts. \nYou should not reference this mesh for shape accuracy', '', 3),
            ('Hide', 'Hide', 'Hide Avatar Mesh', '', 4)
        ],
        default='Male 1.5',
        update= lambda s, c: setMaleFemaleAttachment(s, c)
    )
    head_gender :bpy.props.EnumProperty(
        items=[
            ('Male', 'Male', 'Set Mesh to Male', '', 0),
            ('Female', 'Female', 'Set Mesh to Female', '', 1)
        ],
        default='Male',
        update= lambda s, c: setMaleFemaleHead(s, c)
    )
    furniture_type :bpy.props.EnumProperty(
        items=[
            ('Floor', 'Floor', 'Set Furniture Type to Floor', '', 0),
            ('Wall', 'Wall', 'Set Furniture Type to Wall', '', 1),
            ('Ceiling', 'Ceiling', 'Set Furniture Type to Ceiling', '', 2),
        ],
        default='Floor'
    )
    wall_type :bpy.props.EnumProperty(
        items=[
            ('North', 'North', 'Set Wall Direction to Y', '', 0),
            ('South', 'South', 'Set Wall Direction to -Y', '', 1),
            ('East', 'East', 'Set Wall Direction to X', '', 2),
            ('West', 'West', 'Set Wall Direction to -X', '', 3)
        ],
        default='North'
    )

    node_spacing :bpy.props.FloatProperty(
        name= "Node Spacing",
        description= "How much space should be made between this node and the duplicate",
        default= 3,
        soft_min= 1,
        soft_max= 10
    )
    
    furn_node_spacing :bpy.props.FloatProperty(
        name= "Node Spacing",
        description= "How much space should be made between this node and the duplicate",
        default= 3,
        soft_min= 1,
        soft_max= 10
    )

    custom_seat :bpy.props.StringProperty(
        name= "",
        description= "Name a Custom Seat",
        default= "Custom"
    )
    custom_seat_Furn :bpy.props.StringProperty(
        name= "",
        description= "Name a Custom Seat",
        default= "Custom"
    )
    
    isPose :bpy.props.BoolProperty(
        name= "Pose Mode",
        description= "Create a pose instead of an animation",
        default= False,
        update= lambda s, c: PoseLen(s, c)
    )
    exportAll :bpy.props.BoolProperty(
        name= "Export All Bones",
        description= "Export all bones regardless of whether it has any animation frames",
        default= False
    )
    exportClothing :bpy.props.BoolProperty(
        name= "Export Clothing",
        description= "Export any clothing meshes bound to the avatar",
        default= False
    )

    enableMorph :bpy.props.BoolProperty(
        name= "Morph Controls",
        description= "Enable or Disable the Facial Morph Controls",
        default= True,
        update= lambda s, c: ShowHideMorph(s, c)
    )

    leftArmIK :bpy.props.BoolProperty(
        name= "Left Arm IK",
        description= "Should the left arm use IK",
        default= True,
        update= lambda s, c: ChangeIK(s, c)
    )
    rightArmIK :bpy.props.BoolProperty(
        name= "Right Arm IK",
        description= "Should the right arm use IK",
        default= True,
        update= lambda s, c: ChangeIK(s, c)
    )
    leftLegIK :bpy.props.BoolProperty(
        name= "Left Leg IK",
        description= "Should the left leg use IK",
        default= True,
        update= lambda s, c: ChangeIK(s, c)
    )
    rightLegIK :bpy.props.BoolProperty(
        name= "Right Leg IK",
        description= "Should the right leg use IK",
        default= True,
        update= lambda s, c: ChangeIK(s, c)
    )

    leftArmIso :bpy.props.BoolProperty(
        name= "Left Arm Isolated",
        description= "Should the left arm move isolated to the body",
        default= True,
        update= lambda s, c: ChangeIK(s, c)
    )
    rightArmIso :bpy.props.BoolProperty(
        name= "Right Arm IK",
        description= "Should the right arm move isolated to the body",
        default= True,
        update= lambda s, c: ChangeIK(s, c)
    )
    leftLegIso :bpy.props.BoolProperty(
        name= "Left Leg IK",
        description= "Should the left leg move isolated to the body",
        default= True,
        update= lambda s, c: ChangeIK(s, c)
    )
    rightLegIso :bpy.props.BoolProperty(
        name= "Right Leg IK",
        description= "Should the right leg move isolated to the body",
        default= True,
        update= lambda s, c: ChangeIK(s, c)
    )


    seeThroughNum :bpy.props.IntProperty(
        name= "",
        description="Which number SeeThrough node to link to",
        default= 1,
        min= 1,
        soft_max= 99
    )
    seeThroughNumFurn :bpy.props.IntProperty(
        name= "",
        description="Which number SeeThrough node to link to",
        default= 1,
        min= 1,
        soft_max= 99
    )

    showMCG :bpy.props.BoolProperty(
        name= "Show MCG Reference",
        description= "Show a reference avatar with the MCG skin to reference while making body part products",
        default= False,
        update= lambda s, c: ShowHideMCG(s, c)
    )
    MCGSlider :bpy.props.FloatProperty(
        name= "MCG Reference Size",
        description= "Change the size of the MCG to get an idea of how big the MCG should be",
        default= 0,
        min= 0,
        max= 1,
        update= lambda s, c: ScaleMCG(s, c)
    )



class IMVUTOOL_PT_room_panel(bpy.types.Panel): #ROOM PANEL
    bl_label = "Room Tool"
    bl_idname = "IMVUTOOL_PT_room_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "IMVU Studio Toolkit"
    bl_options = {'DEFAULT_CLOSED'}
 
    def draw(self, context):
        layout = self.layout
        scene = context.scene
        imvutool = scene.imvu_tool
        ButtonActive = False
        someExist = False
        isSeeThrough = False
        isWall = False
        # canDup = False
        canAddNodes = False

        for col in bpy.context.view_layer.layer_collection.children:
            if col.name == "ROOM_EXPORT":
                ButtonActive = True

        for collection in bpy.data.collections:
            if collection.name == "ROOM_EXPORT":
                for obj in collection.all_objects:
                    if "SeeThrough" in obj.name:
                        isSeeThrough = True

        if imvutool.furniture_type == "Wall":
            isWall = True
            


        disabledCollections = ["Attachment_Scene", "FURNITURE_EXPORT", "Clothing_Scene", "Animation_Scene", "Head_Scene"]
        for each in disabledCollections:
            for col in bpy.context.view_layer.layer_collection.children:
                if col.name == each:
                    someExist = True

        dupDirN = "Up"
        dupDirS = "Down"
        for obj in bpy.context.selected_objects:
            if ("Ceiling" in obj.name) or ("Floor" in obj.name) or ("Seat" in obj.name):
                dupDirN = "Forward"
                dupDirS = "Backward"
            if "Wall" in obj.name:
                dupDirN = "Up"
                dupDirS = "Down"
            if "Seat" in obj.name:
                canAddNodes = True


        box1 = layout.box()
        box1.enabled = not someExist
        row0 = box1.row()
        row0.prop(imvutool, "room_size_x")
        row0.prop(imvutool, "room_size_y")
        row0.prop(imvutool, "room_size_z")
        row1 = box1.row()
        row1.enabled = not ButtonActive
        row1.operator("imvutool.room_operator", text= "Create Room", icon= "CUBE")

        if(ButtonActive):
            box2 = layout.box()
            box2.enabled = ButtonActive
            row_radio = box2.row()
            row_radio.prop(imvutool, "furniture_type", expand= True)
            row_radio2 = box2.row()
            row_radio2.enabled = isWall
            row_radio2.prop(imvutool, "wall_type", expand= True)
            box2.row().operator("imvutool.room_furn_operator", text= "Furniture", icon= "PLUS")
            
            box7 = layout.box()
            box7.enabled = ButtonActive
            # box7.enabled = canDup
            row_Grid1 = box7.row()
            row_Grid1.label(text= "")
            row_Grid1.operator("imvutool.room_n_operator", text= dupDirN)
            row_Grid1.label(text= "")
            row_Grid2 = box7.row()
            row_Grid2.operator("imvutool.room_w_operator", text=" Left ")
            row_Grid2.prop(imvutool, "node_spacing")
            row_Grid2.operator("imvutool.room_e_operator", text=" Right ")
            row_Grid3 = box7.row()
            row_Grid3.label(text= "")
            row_Grid3.operator("imvutool.room_s_operator", text= dupDirS)
            row_Grid3.label(text= "")
            

            box3 = layout.box()
            box3.enabled = ButtonActive
            row_idle = box3.row()
            row_idle.operator("imvutool.room_idle_operator", text= "Idle", icon= "PLUS")

            row_stand = box3.row()
            row_stand.operator("imvutool.room_standing_operator", text= "Standing", icon= "PLUS")

            row_sit = box3.row()
            row_sit.operator("imvutool.room_sitting_operator", text= "Sitting", icon= "PLUS")

            box4 = layout.box()
            box4.enabled = ButtonActive
            row_text = box4.row()
            row_text.prop(imvutool, "custom_seat")
            row_custom = box4.row()
            row_custom.operator("imvutool.room_custom_operator", text= "Custom", icon= "PLUS")
            
            box5 = layout.box()
            box5.enabled = ButtonActive
            box5.enabled = canAddNodes
            row_add = box5.row()
            row_add.operator("imvutool.room_add_catch_operator", text= "Catcher", icon= "DECORATE_LINKED")
            row_add.operator("imvutool.room_add_handle_operator", text= "Handle", icon= "DECORATE_LINKED")
            row_del = box5.row()
            row_del.operator("imvutool.room_del_catch_operator", text= "Catcher", icon= "UNLINKED")
            row_del.operator("imvutool.room_del_handle_operator", text= "Handle", icon= "UNLINKED")

            box6 = layout.box()
            box6.enabled = ButtonActive
            row_seeThrough = box6.row()
            row_seeThrough.operator("imvutool.room_seethrough_operator", text= "Create See Through Node", icon= "PLUS")
            row_seeThrough2 = box6.row()
            row_seeThrough2.enabled = isSeeThrough
            row_seeThrough2.operator("imvutool.room_seethroughbind_operator", text= "Link To SeeThrough", icon= "DECORATE_LINKED")
            row_unlink = box6.row()
            row_unlink.operator("imvutool.room_seethroughunbind_operator", text= "Unlink From SeeThrough", icon= "UNLINKED")

class IMVUTOOL_OT_room_op(bpy.types.Operator): #Create Room
    bl_label = "Create Room"
    bl_idname = "imvutool.room_operator"
    bl_description = "Create a Room Based on the Above Dimensions"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool
        if not checkMega():
            bpy.ops.imvutool.megascene('INVOKE_DEFAULT')
            return{'FINISHED'}

        room_path = GetPathToFile(self, "TEX_ScaleRoom.png")
        cube_path = GetPathToFile(self, "TEX_ScaleCube.png")

        bpy.context.space_data.shading.type = 'MATERIAL'

        file_path = GetPathToFile(self, "IMVUMegaScene.blend")

        if file_path:        
            inner_path = 'Collection'
            object_name = "Mannequins"

            DelInitialCollection()

            bpy.ops.wm.append(
                            filepath=os.path.join(file_path, inner_path, object_name),
                            directory=os.path.join(file_path, inner_path),
                            filename=object_name
                            )
            
            bpy.data.objects['MannequinSitting'].location.x = -7.5
            bpy.data.objects['MannequinSitting'].location.y = -1.5
            bpy.data.objects['MannequinStanding'].location.x = -6

        isRoom = False
        for o in bpy.context.scene.objects:
            if o.name == "Room_Reference":
                bpy.ops.object.mode_set(mode= 'OBJECT')
                bpy.ops.object.select_all(action='DESELECT')
                bpy.data.objects['Room_Reference'].select_set(True)
                bpy.ops.object.delete()
            else:
                if o.name == "Skeleton.Room":
                    isRoom = True
                    imvutool.dontHideUI = True

        if isRoom:
            self.report({"WARNING"}, "A Room Already Exists!")
        if not isRoom:
            self.master_collection = bpy.context.scene.collection

            # Create the REFERENCE Collection
            col_room_export = bpy.data.collections.new("REFERENCE")
            root_col = bpy.context.scene.collection
            root_col.children.link(col_room_export)


            ########################
            # REFERENCE COLLECTION #
            ########################

            # Create the initial room with backface culling on and named Room_Ref
            self.layer_collection = bpy.data.collections["REFERENCE"]
            bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(0, 0, 20), scale=(40, 40, 40))
            roomMesh = bpy.context.selected_objects[0]
            roomMesh.name = "Room_Ref"

            for area in bpy.context.screen.areas: 
                if area.type == 'VIEW_3D':
                    for space in area.spaces: 
                        if space.type == 'VIEW_3D':
                            space.shading.type = 'MATERIAL'
            
            bpy.ops.object.mode_set(mode= 'EDIT')
            bpy.ops.mesh.flip_normals()

            bpy.ops.material.new()
            backfaceMat = bpy.data.materials[-1]
            backfaceMat.name = "M_Room"
            backfaceMat.use_backface_culling = True
            bpy.ops.object.material_slot_add()
            context.object.active_material = backfaceMat

            bpy.ops.object.mode_set(mode= 'OBJECT')
            bpy.ops.object.select_all(action='DESELECT')
            bpy.data.objects["Room_Ref"].select_set(True)
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.uv.smart_project()

            bpy.ops.object.mode_set(mode='OBJECT')
            backfaceMat.use_nodes = True
            bsdf = backfaceMat.node_tree.nodes["Principled BSDF"]
            texImage = backfaceMat.node_tree.nodes.new('ShaderNodeTexImage')
            if room_path:
                texImage.image = bpy.data.images.load(room_path)
            backfaceMat.node_tree.links.new(bsdf.inputs['Base Color'], texImage.outputs['Color'])
            bpy.data.materials["M_Room"].node_tree.nodes["Image Texture"].interpolation = 'Closest'
            bpy.ops.object.select_all(action='DESELECT')

            bpy.ops.object.mode_set(mode= 'OBJECT')
            bpy.context.scene.tool_settings.use_transform_correct_face_attributes = True

            ob = bpy.context.scene.objects["Room_Ref"]
            bpy.context.view_layer.objects.active = ob
            ob.select_set(True)
        
            xVal = bpy.context.object.dimensions[0]
            yVal = bpy.context.object.dimensions[1]
            zVal = bpy.context.object.dimensions[2]
            bpy.ops.object.mode_set(mode= 'EDIT')
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.transform.resize(value=(imvutool.room_size_x/xVal, imvutool.room_size_y/yVal, imvutool.room_size_z/zVal))
            bpy.context.object.location[2] = imvutool.room_size_z / 2

            bpy.ops.object.mode_set(mode= 'OBJECT')
            bpy.ops.object.select_all(action='DESELECT')
            self.layer_collection.objects.link(context.object) #link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection

            
            #ScaleCube_Ref
            bpy.ops.mesh.primitive_cube_add(size=3.13, enter_editmode=False, align='WORLD', location=(-7.84016, -1.53243, 3.13/2), scale=(1, 1, 1))
            scaleCube01 = bpy.context.selected_objects[0]
            scaleCube01.name = "ScaleCube_Ref"
            
            bpy.ops.material.new()
            cubeMat = bpy.data.materials[-1]
            cubeMat.name = "M_Cube"
            bpy.ops.object.material_slot_add()
            context.object.active_material = cubeMat

            bpy.ops.object.mode_set(mode= 'OBJECT')
            bpy.ops.object.select_all(action='DESELECT')
            bpy.data.objects["ScaleCube_Ref"].select_set(True)
            cubeMat.use_nodes = True
            bsdf = cubeMat.node_tree.nodes["Principled BSDF"]
            texImage = cubeMat.node_tree.nodes.new('ShaderNodeTexImage')
            if cube_path:
                texImage.image = bpy.data.images.load(cube_path)
            cubeMat.node_tree.links.new(bsdf.inputs['Base Color'], texImage.outputs['Color'])
            bpy.data.materials["M_Cube"].node_tree.nodes["Image Texture"].interpolation = 'Closest'
            bpy.ops.object.select_all(action='DESELECT')

            bpy.ops.object.mode_set(mode= 'OBJECT')

            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection



            # Create the ROOM_EXPORT Collection
            col_room_export = bpy.data.collections.new("ROOM_EXPORT")
            root_col = bpy.context.scene.collection
            root_col.children.link(col_room_export)


            #########################
            # ROOM NODES COLLECTION #
            #########################

            self.layer_collection = bpy.data.collections["ROOM_EXPORT"] #Set collection

            # Skeleton.Room
            bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
            roomRoot = bpy.context.selected_objects[0]
            roomRoot.name = "Skeleton.Room"
            bpy.context.object.empty_display_size = 2
            bpy.context.object.show_name = True
            bpy.context.object.show_in_front = True
            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection

            #Camera_Target
            bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 6), scale=(1, 1, 1), rotation=(math.radians(-90), math.radians(180), 0))
            cameraTarget = bpy.context.selected_objects[0]
            cameraTarget.name = "camera.01.01.target"
            bpy.context.object.empty_display_size = 2
            bpy.context.object.show_name = True
            bpy.context.object.show_in_front = True
            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection
            cameraTarget.parent = roomRoot

            #Camera_Root
            bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, -30, 6), scale=(1, 1, 1), rotation=(math.radians(90), 0, 0))
            cameraRoot = bpy.context.selected_objects[0]
            cameraRoot.name = "camera.01.01.root"
            bpy.context.object.empty_display_size = 2
            bpy.context.object.show_name = True
            bpy.context.object.show_in_front = True
            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection
            cameraRoot.parent = roomRoot
            bpy.ops.object.constraint_add(type='TRACK_TO')
            bpy.context.object.constraints["Track To"].target = cameraTarget

            #Avatar Nodes Group
            bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
            avatarNodes = bpy.context.selected_objects[0]
            avatarNodes.name = "AvatarNodes"
            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection
            avatarNodes.parent = roomRoot

            #Lighting Nodes Group
            bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
            lightingNodes = bpy.context.selected_objects[0]
            lightingNodes.name = "LightingNodes"
            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection
            lightingNodes.parent = roomRoot

            #Furniture Nodes Group
            bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
            furnitureNodes = bpy.context.selected_objects[0]
            furnitureNodes.name = "FurnitureNodes"
            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection
            furnitureNodes.parent = roomRoot
            
            #Omni01
            bpy.ops.object.light_add(type='POINT', align='WORLD', location=(5, 0, 25), scale=(1, 1, 1))
            omniLight = bpy.context.selected_objects[0]
            omniLight.name = "Omni01"
            bpy.context.object.data.energy = 10
            bpy.context.object.data.shadow_soft_size = 40
            bpy.context.object.show_name = True
            bpy.context.object.show_in_front = True
            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection
            omniLight.parent = lightingNodes

            ######################
            # SEATING COLLECTION #
            ######################

            self.layer_collection = bpy.data.collections["ROOM_EXPORT"] #Set collection

            for x in range(1, 7):
                #Seatxx_Standing
                bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=((x-1)*3, 0, 0), scale=(1, 1, 1))
                seat = bpy.context.selected_objects[0]
                seat.name = "Seat" + str(x).zfill(2) + ".Standing"
                bpy.context.object.empty_display_size = 1
                bpy.context.object.show_name = True
                bpy.context.object.show_in_front = True
                self.layer_collection.objects.link(context.object) #Link with collection
                self.master_collection.objects.unlink(context.object) #Unlink from master collection
                seat.parent = avatarNodes


        return {'FINISHED'}

class IMVUTOOL_OT_room_op1(bpy.types.Operator): #Add Funiture
    bl_label = "Add Furniture Seat"
    bl_idname = "imvutool.room_furn_operator"
    bl_description = "Create a Piece of Furniture Based on the Above Selection"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool
        self.master_collection = bpy.context.scene.collection
        self.layer_collection = bpy.data.collections["ROOM_EXPORT"] #Set collection

        scene_collection = bpy.context.view_layer.layer_collection
        bpy.context.view_layer.active_layer_collection = scene_collection

        if imvutool.furniture_type == "Floor":
            numFloors = 1
            floorNum = str(numFloors).zfill(2)

            floorList = []

            for each in self.layer_collection.objects:
                floorList.append(str(each))

            for o in sorted(floorList):
                if "Floor." + str(numFloors).zfill(2) in o:
                    numFloors += 1
                    
                seat_str = str(numFloors)
                floorNum = seat_str.zfill(2)
            
            #Furniture_Floor_xx
            bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
            furnFloor = bpy.context.selected_objects[0]
            furnFloor.name = ("furniture.Floor." + floorNum)
            bpy.context.object.empty_display_size = 1
            bpy.context.object.show_name = True
            bpy.context.object.show_in_front = True
            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection
            furnFloor.parent = bpy.data.objects['FurnitureNodes']
        
        if imvutool.furniture_type == "Wall":
            numWalls = 1
            wallNum = str(numWalls).zfill(2)

            wallList = []

            for each in self.layer_collection.objects:
                wallList.append(str(each))

            for o in sorted(wallList):
                if "Wall." + str(numWalls).zfill(2) in o:
                    numWalls += 1
                    
                seat_str = str(numWalls)
                wallNum = seat_str.zfill(2)
            
            if imvutool.wall_type == "North":
                wallLoc = (0, imvutool.room_size_y / 2, imvutool.room_size_z / 2)
                wallRot = (math.radians(-90), math.radians(180), math.radians(180))
            if imvutool.wall_type == "South":
                wallLoc = (0, -imvutool.room_size_y / 2, imvutool.room_size_z / 2)
                wallRot = (math.radians(-90), math.radians(180), math.radians(0))
            if imvutool.wall_type == "East":
                wallLoc = (imvutool.room_size_x / 2, 0, imvutool.room_size_z / 2)
                wallRot = (math.radians(-90), math.radians(180), math.radians(90))
            if imvutool.wall_type == "West":
                wallLoc = (-imvutool.room_size_x / 2, 0, imvutool.room_size_z / 2)
                wallRot = (math.radians(-90), math.radians(180), math.radians(-90))

            #furniture_Wall.xx
            bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=wallLoc, scale=(1, 1, 1), rotation=wallRot)
            furnWall = bpy.context.selected_objects[0]
            furnWall.name = ("furniture.Wall." + wallNum)
            bpy.context.object.empty_display_size = 1
            bpy.context.object.show_name = True
            bpy.context.object.show_in_front = True
            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection
            furnWall.parent = bpy.data.objects['FurnitureNodes']
        
        if imvutool.furniture_type == "Ceiling":
            
            numCeils = 1
            ceilNum = str(numCeils).zfill(2)

            ceilList = []

            for each in self.layer_collection.objects:
                ceilList.append(str(each))

            for o in sorted(ceilList):
                if "Ceiling." + str(numCeils).zfill(2) in o:
                    numCeils += 1
                    
                seat_str = str(numCeils)
                ceilNum = seat_str.zfill(2)
            
            #Furniture_Ceiling_xx
            bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, imvutool.room_size_z), scale=(1, 1, 1), rotation= (0, math.radians(180), 0))
            furnCeil = bpy.context.selected_objects[0]
            furnCeil.name = ("furniture.Ceiling." + ceilNum)
            bpy.context.object.empty_display_size = 1
            bpy.context.object.show_name = True
            bpy.context.object.show_in_front = True
            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection
            furnCeil.parent = bpy.data.objects['FurnitureNodes']
        
        return {'FINISHED'}

class IMVUTOOL_OT_room_op2(bpy.types.Operator): #Add Sitting
    bl_label = "Add Sitting"
    bl_idname = "imvutool.room_sitting_operator"
    bl_description = "Create a sitting Seat Node. \nSelect C / P to create a Catcher and a Pitcher node. \nSelect Handle to create a Handle node"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):

        AddSeat(self, context, "Sitting", True, True, "ROOM_EXPORT")

        return {'FINISHED'}

class IMVUTOOL_OT_room_op3(bpy.types.Operator): #Add Standing
    bl_label = "Add Standing Seat"
    bl_idname = "imvutool.room_standing_operator"
    bl_description = "Create a standing Seat Node. \nSelect Catch / Pitch to create a Catcher and a Pitcher node."
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        AddSeat(self, context, "Standing", True, True, "ROOM_EXPORT")

        return {'FINISHED'}

class IMVUTOOL_OT_room_op4(bpy.types.Operator): #Add Idle
    bl_label = "Add Idle Seat"
    bl_idname = "imvutool.room_idle_operator"
    bl_description = "Create an idle Seat Node. \nSelect Catch / Pitch to create a Catcher and a Pitcher node."
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        AddSeat(self, context, "Idle", True, True, "ROOM_EXPORT")

        return {'FINISHED'}

class IMVUTOOL_OT_room_op5(bpy.types.Operator): #Add Custom
    bl_label = "Add Custom Seat"
    bl_idname = "imvutool.room_custom_operator"
    bl_description = "Create a custom Seat Node based on the name above. \nSelect Catch / Pitch to create a Catcher and a Pitcher node."
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool

        AddSeat(self, context, imvutool.custom_seat, True, True, "ROOM_EXPORT")

        return {'FINISHED'}

class IMVUTOOL_OT_room_op6(bpy.types.Operator): #Add See Through
    bl_label = "Create See Through Node"
    bl_idname = "imvutool.room_seethrough_operator"
    bl_description = "Create a see through node. \nYou must place it where you would like."
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):

        CreateSeeThrough(self, context, "ROOM_EXPORT", "Skeleton.Room")

        return {'FINISHED'}

class IMVUTOOL_OT_room_op7(bpy.types.Operator): #Link See Through
    bl_label = "Link mesh to SeeThrough"
    bl_idname = "imvutool.room_seethroughbind_operator"
    bl_description = "Link a mesh to a specific seethrough node."
    
    def execute(self, context):
        
        LinkSeeThrough(self)

        return {'FINISHED'}

class IMVUTOOL_OT_room_op8(bpy.types.Operator): #Unlink See Through
    bl_label = "Unlink mesh from SeeThrough"
    bl_idname = "imvutool.room_seethroughunbind_operator"
    bl_description = "Unlink a mesh from a specific seethrough node."
    
    def execute(self, context):
        
        UnlinkSeeThrough(self, "Skeleton.Room")

        return {'FINISHED'}

class IMVUTOOL_OT_room_op9(bpy.types.Operator): #Add Catch/Pitch
    bl_label = "Add Catch/Pitch"
    bl_idname = "imvutool.room_add_catch_operator"
    bl_description = "Add a catcher and pitcher node to the selected seat"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        AddNode(self, context, "Add Catch", "ROOM_EXPORT")

        return {'FINISHED'}

class IMVUTOOL_OT_room_op10(bpy.types.Operator): #Del Catch/Pitch
    bl_label = "Delete Catch/Pitch"
    bl_idname = "imvutool.room_del_catch_operator"
    bl_description = "Remove catcher and pitcher nodes from the selected seat"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        AddNode(self, context, "Del Catch", "ROOM_EXPORT")

        return {'FINISHED'}
        
class IMVUTOOL_OT_room_op11(bpy.types.Operator): #Add Handle
    bl_label = "Add Handle"
    bl_idname = "imvutool.room_add_handle_operator"
    bl_description = "Add a handle node to the selected seat"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        AddNode(self, context, "Add Handle", "ROOM_EXPORT")

        return {'FINISHED'}
        
class IMVUTOOL_OT_room_op12(bpy.types.Operator): #Del Handle
    bl_label = "Delete Handle"
    bl_idname = "imvutool.room_del_handle_operator"
    bl_description = "Remove handle node from the selected seat"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        AddNode(self, context, "Del Handle", "ROOM_EXPORT")

        return {'FINISHED'}
   
class IMVUTOOL_OT_room_op13(bpy.types.Operator): #N
    bl_label = "North"
    bl_idname = "imvutool.room_n_operator"
    bl_description = "Duplicate a node in the local Y direction. \nTip: Select multiple to easily make a grid"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool
        
        DuplicateNode(self, context, "N", imvutool.node_spacing, "ROOM_EXPORT")
        
        return {'FINISHED'}

class IMVUTOOL_OT_room_op14(bpy.types.Operator): #W
    bl_label = "West"
    bl_idname = "imvutool.room_w_operator"
    bl_description = "Duplicate a node in the local -X direction. \nTip: Select multiple to easily make a grid"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool
        
        DuplicateNode(self, context, "W", imvutool.node_spacing, "ROOM_EXPORT")
        
        return {'FINISHED'}

class IMVUTOOL_OT_room_op15(bpy.types.Operator): #E
    bl_label = "East"
    bl_idname = "imvutool.room_e_operator"
    bl_description = "Duplicate a node in the local X direction. \nTip: Select multiple to easily make a grid"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool
        
        DuplicateNode(self, context, "E", imvutool.node_spacing, "ROOM_EXPORT")
        
        return {'FINISHED'}

class IMVUTOOL_OT_room_op16(bpy.types.Operator): #S
    bl_label = "South"
    bl_idname = "imvutool.room_s_operator"
    bl_description = "Duplicate a node in the local -Y direction. \nTip: Select multiple to easily make a grid"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool
        
        DuplicateNode(self, context, "S", imvutool.node_spacing, "ROOM_EXPORT")
        
        return {'FINISHED'}




class IMVUTOOL_PT_furniture_panel(bpy.types.Panel): #FURNITURE PANEL
    bl_label = "Furniture Tool"
    bl_idname = "IMVUTOOL_PT_furniture_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "IMVU Studio Toolkit"
    bl_options = {'DEFAULT_CLOSED'}
 
    def draw(self, context):
        layout = self.layout
        scene = context.scene
        imvutool = scene.imvu_tool

        ButtonActive = False
        someExist = False
        isSeeThrough = False
        isWall = False
        # canDup = True
        canAddNodes = False


        for col in bpy.context.view_layer.layer_collection.children:
            if col.name == "FURNITURE_EXPORT":
                ButtonActive = True
                
        if imvutool.furniture_type == "Wall":
            isWall = True
            
        disabledCollections = ["Attachment_Scene", "ROOM_EXPORT", "Clothing_Scene", "Animation_Scene", "Head_Scene"]
        for each in disabledCollections:
            for col in bpy.context.view_layer.layer_collection.children:
                if col.name == each:
                    someExist = True

        for collection in bpy.data.collections:
            if collection.name == "FURNITURE_EXPORT":
                for obj in collection.all_objects:
                    if "SeeThrough" in obj.name:
                        isSeeThrough = True

        for obj in bpy.context.selected_objects:
            if "Seat" in obj.name:
                canAddNodes = True

        dupDirN = "Up"
        dupDirS = "Down"
        for obj in bpy.context.selected_objects:
            if ("Ceiling" in obj.name) or ("Floor" in obj.name) or ("Seat" in obj.name):
                dupDirN = "Forward"
                dupDirS = "Backward"
            if "Wall" in obj.name:
                dupDirN = "Up"
                dupDirS = "Down"
            if "Seat" in obj.name:
                canAddNodes = True
            
        box1 = layout.box()
        box1.enabled = not someExist
        row = box1.row()
        row.enabled = not ButtonActive
        row.operator("imvutool.furn_furn_operator", icon= "LIGHT_DATA")
        
        if(ButtonActive):
            box2 = layout.box()
            box2.enabled = ButtonActive
            row_radio = box2.row()
            row_radio.prop(imvutool, "furniture_type", expand= True)
            row_radio2 = box2.row()
            row_radio2.enabled = isWall
            row_radio2.prop(imvutool, "wall_type", expand= True)
            box2.row().operator("imvutool.furn_furniture_operator", text= "Furniture", icon= "PLUS")
            
            box7 = layout.box()
            box7.enabled = ButtonActive
            # box7.enabled = canDup
            row_Grid1 = box7.row()
            row_Grid1.label(text= "")
            row_Grid1.operator("imvutool.furn_n_operator", text= dupDirN)
            row_Grid1.label(text= "")
            row_Grid2 = box7.row()
            row_Grid2.operator("imvutool.furn_w_operator", text=" Left ")
            row_Grid2.prop(imvutool, "furn_node_spacing")
            row_Grid2.operator("imvutool.furn_e_operator", text=" Right ")
            row_Grid3 = box7.row()
            row_Grid3.label(text= "")
            row_Grid3.operator("imvutool.furn_s_operator", text= dupDirS)
            row_Grid3.label(text= "")

            box3 = layout.box()
            box3.enabled = ButtonActive
            row_idle = box3.row()
            row_idle.operator("imvutool.furn_idle_operator", text= "Idle", icon= "PLUS")

            row_stand = box3.row()
            row_stand.operator("imvutool.furn_standing_operator", text= "Standing", icon= "PLUS")

            row_sit = box3.row()
            row_sit.operator("imvutool.furn_sitting_operator", text= "Sitting", icon= "PLUS")

            box4 = layout.box()
            box4.enabled = ButtonActive
            row_text = box4.row()
            row_text.prop(imvutool, "custom_seat_Furn")
            row_custom = box4.row()
            row_custom.operator("imvutool.furn_custom_operator", text= "Custom", icon= "PLUS")

            box5 = layout.box()
            box5.enabled = ButtonActive
            box5.enabled = canAddNodes
            row_add = box5.row()
            row_add.operator("imvutool.furn_add_catch_operator", text= "Catcher", icon= "DECORATE_LINKED")
            row_add.operator("imvutool.furn_add_handle_operator", text= "Handle", icon= "DECORATE_LINKED")
            row_del = box5.row()
            row_del.operator("imvutool.furn_del_catch_operator", text= "Catcher", icon= "UNLINKED")
            row_del.operator("imvutool.furn_del_handle_operator", text= "Handle", icon= "UNLINKED")

            box6 = layout.box()
            box6.enabled = ButtonActive
            row_seeThrough = box6.row()
            row_seeThrough.operator("imvutool.furn_seethrough_operator", text= "Create See Through Node", icon= "PLUS")
            row_seeThrough2 = box6.row()
            row_seeThrough2.enabled = isSeeThrough
            row_seeThrough2.operator("imvutool.furn_seethroughbind_operator", text= "Link To SeeThrough", icon= "DECORATE_LINKED")
            row_unlink_furn = box6.row()
            row_unlink_furn.operator("imvutool.furn_seethroughunbind_operator", text= "Unlink From SeeThrough", icon= "UNLINKED")
        
class IMVUTOOL_OT_furniture_op(bpy.types.Operator): #Create Furniture Base
    bl_label = "Create Furniture"
    bl_idname = "imvutool.furn_furn_operator"
    bl_description = "Create a Furniture Guide"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool
        if not checkMega():
            bpy.ops.imvutool.megascene('INVOKE_DEFAULT')
            return{'FINISHED'}
        
        furn_path = GetPathToFile(self, "TEX_ScaleSeat.png")

        bpy.context.space_data.shading.type = 'MATERIAL'
        
        
        file_path = GetPathToFile(self, "IMVUMegaScene.blend")

        if file_path:        
            inner_path = 'Collection'
            object_name = "Mannequins"

            DelInitialCollection()

            bpy.ops.wm.append(
                            filepath=os.path.join(file_path, inner_path, object_name),
                            directory=os.path.join(file_path, inner_path),
                            filename=object_name
                            )
            
        isFurn = False

        if isFurn:
            self.report({"WARNING"}, "A Furniture Already Exists!")
        if not isFurn:
            self.master_collection = bpy.context.scene.collection

        bpy.ops.ed.undo_push()
        
        # Create the REFERENCE Collection
        col_furn_export = bpy.data.collections.new("REFERENCE")
        root_col = bpy.context.scene.collection
        root_col.children.link(col_furn_export)

        ###################
        # MESH COLLECTION #
        ###################

        self.layer_collection = bpy.data.collections["REFERENCE"] #Set collection

        #ScaleCube_Ref
        bpy.ops.mesh.primitive_cube_add(size=1, enter_editmode=False, align='WORLD', location=(0, 0, 3.13/2), scale=(6, 3.13, 3.13))
        scaleCube01 = bpy.context.selected_objects[0]
        scaleCube01.name = "ScaleCube_Ref"

        bpy.ops.object.mode_set(mode= 'OBJECT')
        bpy.ops.object.select_all(action='DESELECT')
        bpy.data.objects["ScaleCube_Ref"].select_set(True)
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.uv.smart_project()
        bpy.ops.object.mode_set(mode='OBJECT')
        scaleMat = bpy.data.materials.new(name="M_ScaleSeat")
        bpy.context.active_object.data.materials.append(scaleMat)
        scaleMat.use_nodes = True
        bsdf = scaleMat.node_tree.nodes["Principled BSDF"]
        texImage = scaleMat.node_tree.nodes.new('ShaderNodeTexImage')
        if furn_path:
            texImage.image = bpy.data.images.load(furn_path)
        scaleMat.node_tree.links.new(bsdf.inputs['Base Color'], texImage.outputs['Color'])
        bpy.ops.object.select_all(action='DESELECT')

        self.layer_collection.objects.link(context.object) #Link with collection
        self.master_collection.objects.unlink(context.object) #Unlink from master collection

        # Create the FURNITURE_EXPORT Collection
        col_furn_export = bpy.data.collections.new("FURNITURE_EXPORT")
        root_col = bpy.context.scene.collection
        root_col.children.link(col_furn_export)



        ###############################
        # FURNITURE NODES COLLECTION #
        ##############################

        self.master_collection = bpy.context.scene.collection
        self.layer_collection = bpy.data.collections["FURNITURE_EXPORT"] #Set collection
        
        bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
        furnitureRoot = bpy.context.selected_objects[0]
        furnitureRoot.name = "Root"
        bpy.context.object.empty_display_size = 1
        bpy.context.object.show_name = True
        bpy.context.object.show_in_front = True
        self.layer_collection.objects.link(context.object) #Link with collection
        self.master_collection.objects.unlink(context.object) #Unlink from master collection

        #Avatar Nodes Group
        bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
        avatarNodes = bpy.context.selected_objects[0]
        avatarNodes.name = "AvatarNodes"
        self.layer_collection.objects.link(context.object) #Link with collection
        self.master_collection.objects.unlink(context.object) #Unlink from master collection
        avatarNodes.parent = furnitureRoot

        #Furniture Nodes Group
        bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
        furnNodes = bpy.context.selected_objects[0]
        furnNodes.name = "FurnitureNodes"
        self.layer_collection.objects.link(context.object) #Link with collection
        self.master_collection.objects.unlink(context.object) #Unlink from master collection
        furnNodes.parent = furnitureRoot
       

        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op1(bpy.types.Operator): #Add Funiture
    bl_label = "Add Furniture Seat"
    bl_idname = "imvutool.furn_furniture_operator"
    bl_description = "Create a Piece of Furniture Based on the Above Selection"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool
        self.master_collection = bpy.context.scene.collection
        self.layer_collection = bpy.data.collections["FURNITURE_EXPORT"] #Set collection

        scene_collection = bpy.context.view_layer.layer_collection
        bpy.context.view_layer.active_layer_collection = scene_collection

        if imvutool.furniture_type == "Floor":
            numFloors = 1
            floorNum = str(numFloors).zfill(2)

            floorList = []

            for each in self.layer_collection.objects:
                floorList.append(str(each))

            for o in sorted(floorList):
                if "Floor." + str(numFloors).zfill(2) in o:
                    numFloors += 1
                    
                seat_str = str(numFloors)
                floorNum = seat_str.zfill(2)
            
            #furniture.Floor.xx
            bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
            furnFloor = bpy.context.selected_objects[0]
            furnFloor.name = ("furniture.Floor." + floorNum)
            bpy.context.object.empty_display_size = 1
            bpy.context.object.show_name = True
            bpy.context.object.show_in_front = True
            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection
            furnFloor.parent = bpy.data.objects['FurnitureNodes']
        
        if imvutool.furniture_type == "Wall":
            numWalls = 1
            wallNum = str(numWalls).zfill(2)

            wallList = []

            for each in self.layer_collection.objects:
                wallList.append(str(each))

            for o in sorted(wallList):
                if "Wall." + str(numWalls).zfill(2) in o:
                    numWalls += 1
                    
                seat_str = str(numWalls)
                wallNum = seat_str.zfill(2)
            
            if imvutool.wall_type == "North":
                wallLoc = (0, 5, 5)
                wallRot = (math.radians(-90), math.radians(180), math.radians(180))
            if imvutool.wall_type == "South":
                wallLoc = (0, -5, 5)
                wallRot = (math.radians(-90), math.radians(180), math.radians(0))
            if imvutool.wall_type == "East":
                wallLoc = (5, 0, 5)
                wallRot = (math.radians(-90), math.radians(180), math.radians(90))
            if imvutool.wall_type == "West":
                wallLoc = (-5, 0, 5)
                wallRot = (math.radians(-90), math.radians(180), math.radians(-90))

            #furniture_Wall.xx
            bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=wallLoc, scale=(1, 1, 1), rotation=wallRot)
            furnWall = bpy.context.selected_objects[0]
            furnWall.name = ("furniture.Wall." + wallNum)
            bpy.context.object.empty_display_size = 1
            bpy.context.object.show_name = True
            bpy.context.object.show_in_front = True
            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection
            furnWall.parent = bpy.data.objects['FurnitureNodes']
        
        if imvutool.furniture_type == "Ceiling":
            
            numCeils = 1
            ceilNum = str(numCeils).zfill(2)

            ceilList = []

            for each in self.layer_collection.objects:
                ceilList.append(str(each))

            for o in sorted(ceilList):
                if "Ceiling." + str(numCeils).zfill(2) in o:
                    numCeils += 1
                    
                seat_str = str(numCeils)
                ceilNum = seat_str.zfill(2)
            
            #Furniture_Ceiling_xx
            bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0, 0, 10), scale=(1, 1, 1), rotation= (0, math.radians(180), 0))
            furnCeil = bpy.context.selected_objects[0]
            furnCeil.name = ("furniture.Ceiling." + ceilNum)
            bpy.context.object.empty_display_size = 1
            bpy.context.object.show_name = True
            bpy.context.object.show_in_front = True
            self.layer_collection.objects.link(context.object) #Link with collection
            self.master_collection.objects.unlink(context.object) #Unlink from master collection
            furnCeil.parent = bpy.data.objects['FurnitureNodes']
        
        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op2(bpy.types.Operator): #Add Sitting
    bl_label = "Add Sitting"
    bl_idname = "imvutool.furn_sitting_operator"
    bl_description = "Create a sitting Seat Node. \nSelect C / P to create a Catcher and a Pitcher node. \nSelect Handle to create a Handle node"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        AddSeat(self, context, "Sitting", True, True, "FURNITURE_EXPORT")
        
        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op3(bpy.types.Operator): #Add Standing
    bl_label = "Add Standing Seat"
    bl_idname = "imvutool.furn_standing_operator"
    bl_description = "Create a standing Seat Node. \nSelect Catch / Pitch to create a Catcher and a Pitcher node."
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        AddSeat(self, context, "Standing", True, True, "FURNITURE_EXPORT")
        
        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op4(bpy.types.Operator): #Add Idle
    bl_label = "Add Idle Seat"
    bl_idname = "imvutool.furn_idle_operator"
    bl_description = "Create an idle Seat Node. \nSelect Catch / Pitch to create a Catcher and a Pitcher node."
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        AddSeat(self, context, "Idle", True, True, "FURNITURE_EXPORT")
        
        return {'FINISHED'}
     
class IMVUTOOL_OT_furniture_op5(bpy.types.Operator): #Add Custom
    bl_label = "Add Custom Seat"
    bl_idname = "imvutool.furn_custom_operator"
    bl_description = "Create a custom Seat Node based on the name above. \nSelect Catch / Pitch to create a Catcher and a Pitcher node."
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool

        AddSeat(self, context, imvutool.custom_seat_Furn, True, True, "FURNITURE_EXPORT")
        
        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op6(bpy.types.Operator): #Add See Through
    bl_label = "Create See Through Node"
    bl_idname = "imvutool.furn_seethrough_operator"
    bl_description = "Create a see through node. \nYou must place it where you would like."
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):

        CreateSeeThrough(self, context, "FURNITURE_EXPORT", "Root")

        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op7(bpy.types.Operator): #Link See Through
    bl_label = "Link mesh to SeeThrough"
    bl_idname = "imvutool.furn_seethroughbind_operator"
    bl_description = "Link a mesh to a specific seethrough node."
    
    def execute(self, context):
        
        LinkSeeThrough(self)

        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op8(bpy.types.Operator): #Unlink See Through
    bl_label = "Unlink mesh from SeeThrough"
    bl_idname = "imvutool.furn_seethroughunbind_operator"
    bl_description = "Unlink a mesh from a seethrough node."
    
    def execute(self, context):
        
        UnlinkSeeThrough(self, "Root")

        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op9(bpy.types.Operator): #Add Catch/Pitch
    bl_label = "Add Catch/Pitch"
    bl_idname = "imvutool.furn_add_catch_operator"
    bl_description = "Add a catcher and pitcher node to the selected seat"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        AddNode(self, context, "Add Catch", "FURNITURE_EXPORT")

        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op10(bpy.types.Operator): #Del Catch/Pitch
    bl_label = "Del Catch/Pitch"
    bl_idname = "imvutool.furn_del_catch_operator"
    bl_description = "Remove catcher and pitcher nodes from the selected seat"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        AddNode(self, context, "Del Catch", "FURNITURE_EXPORT")

        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op11(bpy.types.Operator): #Add Handle
    bl_label = "Add Handle"
    bl_idname = "imvutool.furn_add_handle_operator"
    bl_description = "Add a handle node to the selected seat"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        AddNode(self, context, "Add Handle", "FURNITURE_EXPORT")

        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op12(bpy.types.Operator): #Del Handle
    bl_label = "Del Handle"
    bl_idname = "imvutool.furn_del_handle_operator"
    bl_description = "Remove handle node from the selected seat"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        AddNode(self, context, "Del Handle", "FURNITURE_EXPORT")

        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op13(bpy.types.Operator): #N
    bl_label = "North"
    bl_idname = "imvutool.furn_n_operator"
    bl_description = "Duplicate a node in the local Y direction. \nTip: Select multiple to easily make a grid"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool
        
        DuplicateNode(self, context, "N", imvutool.furn_node_spacing, "FURNITURE_EXPORT")
        
        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op14(bpy.types.Operator): #W
    bl_label = "West"
    bl_idname = "imvutool.furn_w_operator"
    bl_description = "Duplicate a node in the local -X direction. \nTip: Select multiple to easily make a grid"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool
        
        DuplicateNode(self, context, "W", imvutool.furn_node_spacing, "FURNITURE_EXPORT")
        
        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op15(bpy.types.Operator): #E
    bl_label = "East"
    bl_idname = "imvutool.furn_e_operator"
    bl_description = "Duplicate a node in the local X direction. \nTip: Select multiple to easily make a grid"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool
        
        DuplicateNode(self, context, "E", imvutool.furn_node_spacing, "FURNITURE_EXPORT")
        
        return {'FINISHED'}

class IMVUTOOL_OT_furniture_op16(bpy.types.Operator): #S
    bl_label = "South"
    bl_idname = "imvutool.furn_s_operator"
    bl_description = "Duplicate a node in the local -Y direction. \nTip: Select multiple to easily make a grid"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool
        
        DuplicateNode(self, context, "S", imvutool.furn_node_spacing, "FURNITURE_EXPORT")
        
        return {'FINISHED'}




class IMVUTOOL_PT_attachment_panel(bpy.types.Panel): #ATTACHMENT PANEL
    bl_label = "Attachment Tool"
    bl_idname = "IMVUTOOL_PT_attachment_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "IMVU Studio Toolkit"
    bl_options = {'DEFAULT_CLOSED'}

    

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        imvutool = scene.imvu_tool

        ButtonActive = False
        someExist = False
        global isAligned

        for col in bpy.context.view_layer.layer_collection.children:
            if col.name == "Attachment_Scene":
                ButtonActive = True
        
        disabledCollections = ["ROOM_EXPORT", "FURNITURE_EXPORT", "Clothing_Scene", "Animation_Scene", "Head_Scene"]
        for each in disabledCollections:
            for col in bpy.context.view_layer.layer_collection.children:
                if col.name == each:
                    someExist = True
        

        box1 = layout.box()
        box1.enabled = not someExist

        row2 = box1.row()
        row2.enabled = not ButtonActive
        row2.operator("imvutool.attachment_operator", icon= "ARMATURE_DATA")

        if(ButtonActive):
            box2 = layout.box()
            box2.enabled = ButtonActive

            row3 = box2.row()
            row3.prop(imvutool, "attachment_gender", expand= False, text= "Gender")
            row4 = box2.row()
            row4.prop_search(scene, "bones", bpy.data.collections['Attachment_Skeleton'], "objects", text= "Bone")
            row6 = box2.row()
            row6.operator("imvutool.attachment_setup_operator")

            maleMesh = bpy.data.collections.get("Attachment_Male_Mesh")
            femaleMesh = bpy.data.collections.get("Attachment_Female_Mesh")
            maleMesh_1_5 = bpy.data.collections.get("Attachment_Male_Mesh_1_5")
            femaleMesh_1_5 = bpy.data.collections.get("Attachment_Female_Mesh_1_5")

            if (bpy.data.scenes["Scene"].bones) == None:
                for obj in femaleMesh.objects:
                    if(obj.hide_get() == False):
                        hideAttachment()
                for obj in maleMesh.objects:
                    if(obj.hide_get() == False):
                        hideAttachment()
                for obj in maleMesh_1_5.objects:
                    if(obj.hide_get() == False):
                        hideAttachment()
                for obj in femaleMesh_1_5.objects:
                    if(obj.hide_get() == False):
                        hideAttachment()
            else:
                setMaleFemaleAttachment(self, context)
        
class IMVUTOOL_OT_attachment_op(bpy.types.Operator): #Append Attachment File
    bl_label = "Append Attachment File"
    bl_idname = "imvutool.attachment_operator"
    bl_description = "Append Attachment File"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):

        if not checkMega():
            bpy.ops.imvutool.megascene('INVOKE_DEFAULT')
            return{'FINISHED'}

        file_path = GetPathToFile(self, "IMVUMegaScene.blend")
        if file_path:
            inner_path = 'Collection'
            object_name = "Attachment_Scene"

            bpy.context.space_data.shading.type = 'MATERIAL'

            DelInitialCollection()

            bpy.ops.wm.append(
                            filepath=os.path.join(file_path, inner_path, object_name),
                            directory=os.path.join(file_path, inner_path),
                            filename=object_name
                            )
            setMaleFemaleAttachment(self, context)

        return {'FINISHED'}

class IMVUTOOL_OT_attachment_op2(bpy.types.Operator): #Setup Mesh
    bl_label = "Setup Mesh"
    bl_idname = "imvutool.attachment_setup_operator"
    bl_description = "Sets up the selected mesh"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        self.master_collection = bpy.context.scene.collection

        obj = bpy.context.selected_objects
        boneToBind = bpy.data.scenes["Scene"].bones
        canBind = True
        isArmature = False
        isMesh = False

        myMeshes = []

        bones = ['Neck01', 'Neck02', 'Neck03', 'Neck04', 'Head', 'rtShoulder', 'Pelvis', 
        'Spine01', 'rtHip', 'lfHip', 'lfClavicle', 'rtClavicle', 'Spine02', 'Spine03', 
        'Spine04', 'lfShoulder', 'rtWrist', 'rtElbow', 'rtBicep', 'lfWrist', 'lfElbow', 
        'lfbicep', 'rtToes', 'lfToes', 'rtFoot', 'lfFoot', 'lfCalf', 'rtCalf', 'rtThigh', 
        'lfThigh', 'rtFingerIndex01', 'rtFingerIndex02', 'rtFingerIndex03', 'rtFingerMiddle01', 
        'rtFingerMiddle02', 'rtFingerMiddle03', 'rtFingerPinky01', 'rtFingerPinky02', 'rtFingerPinky03', 
        'rtFingerRing01', 'rtFingerRing02', 'rtFingerRing03', 'rtHand', 'rtmetaCarpal01', 'rtmetaCarpal02', 
        'rtmetaCarpal03', 'rtmetaCarpal04', 'rtmetaCarpal05', 'rtThumb01', 'rtThumb02', 'rtThumb03', 
        'lfFingerIndex01', 'lfFingerIndex02', 'lfFingerIndex03', 'lfFingerMiddle01', 'lfFingerMiddle02', 
        'lfFingerMiddle03', 'lfFingerPinky01', 'lfFingerPinky02', 'lfFingerPinky03', 'lfFingerRing01', 
        'lfFingerRing02', 'lfFingerRing03', 'lfHand', 'lfmetaCarpal01', 'lfmetaCarpal02', 'lfmetaCarpal03', 
        'lfmetaCarpal04', 'lfmetaCarpal05', 'lfThumb01', 'lfThumb02', 'lfThumb03', 'Female03MasterRoot']
        
        if len(obj) == 0:
            self.report({"WARNING"}, "Please select an object to attach!")
        else:
            bpy.ops.object.mode_set(mode= 'OBJECT')

        if boneToBind == None:
            bpy.data.scenes["Scene"].bones = bpy.data.objects["Female03MasterRoot"]
            boneToBind = bpy.data.scenes["Scene"].bones
            canBind = True
            
        if not boneToBind.name in bones:
            canBind = False
            self.report({"WARNING"}, "Please select a valid bone!")
        elif not boneToBind.type == "ARMATURE": 
            canBind = False
            self.report({"WARNING"}, "Please select a valid bone!")
        else:
            if canBind:
                for each in obj:
                    if each.type == "ARMATURE":
                        myArmature = each
                        isArmature = True
                        for child in each.children:
                            if child.type == "MESH":
                                isMesh = True
                                myMeshes.append(child)
                    if each.type == "MESH":
                        isMesh = True
                        myMeshes.append(each)
                    
                if isMesh and not isArmature:
                    armature = bpy.data.objects['Attachment.RIG'].data
                    if "[" in armature.bones[-1].name:
                        armature.bones[-1].name = armature.bones[-1].name.split('[')[0]

                    armature_from = bpy.data.objects['Attachment.RIG']
                    armature_to = bpy.data.objects[boneToBind.name]


                    bpy.context.view_layer.objects.active = bpy.data.objects[str(boneToBind.name)]
                    bpy.ops.object.mode_set(mode='EDIT')
                    selBone = bpy.data.objects[str(boneToBind.name)].data.edit_bones['AttachmentRoot']
                    
                    bpy.context.view_layer.objects.active = bpy.data.objects['Attachment.RIG']

                    armature_from.matrix_world = armature_to.matrix_world
                    bpy.ops.object.mode_set(mode='EDIT')

                    attachmentBone = bpy.data.objects['Attachment.RIG'].data.edit_bones['AttachmentRoot']
                    attachmentBone.tail = (selBone.tail[0], selBone.tail[1], selBone.tail[2])
                    attachmentBone.roll = selBone.roll

                    attachmentBoneNode = bpy.data.objects['Attachment.RIG'].data.edit_bones['AttachmentNode']
                    attachmentBoneNode.tail = (selBone.tail[0], selBone.tail[1], selBone.tail[2])
                    attachmentBoneNode.roll = selBone.roll
                
                    bpy.ops.object.mode_set(mode='OBJECT')

                    for each in obj:
                        verts = []
                        context.view_layer.objects.active = each

                        if not str(each.users_collection[0].name) == "ATTACHMENT_EXPORT":
                            bpy.data.collections['ATTACHMENT_EXPORT'].objects.link(each)
                            self.master_collection.objects.unlink(context.object)
                            
                        bpy.data.objects[str(each.name)].select_set(True)
                        if(len(bpy.context.active_object.vertex_groups) > 0):
                            each.modifiers.clear()
                            each.vertex_groups.clear()

                        group = bpy.context.active_object.vertex_groups.new(name='AttachmentNode')

                        for vert in range(len(bpy.context.object.data.vertices)):
                            verts.append(vert)
                        group.add( verts, 1, 'REPLACE' )

                        bpy.ops.object.modifier_add(type='ARMATURE')
                        bpy.context.object.modifiers["Armature"].object = bpy.data.objects["Attachment.RIG"]

                        boneToBind = bpy.data.scenes["Scene"].bones.name

                    armature = bpy.data.objects['Attachment.RIG'].data
                    armature.bones[-1].name = armature.bones[-1].name + "[" + boneToBind + "]"

                if isMesh and isArmature:
                    armature = bpy.data.objects['Attachment.RIG'].data
                    if "[" in armature.bones[-1].name:
                        armature.bones[-1].name = armature.bones[-1].name.split('[')[0]

                    armature_from = bpy.data.objects['Attachment.RIG']
                    armature_to = bpy.data.objects[boneToBind.name]


                    bpy.context.view_layer.objects.active = bpy.data.objects[str(boneToBind.name)]
                    bpy.ops.object.mode_set(mode='EDIT')
                    selBone = bpy.data.objects[str(boneToBind.name)].data.edit_bones['AttachmentRoot']
                    
                    bpy.context.view_layer.objects.active = bpy.data.objects['Attachment.RIG']

                    armature_from.matrix_world = armature_to.matrix_world
                    bpy.ops.object.mode_set(mode='EDIT')

                    attachmentBone = bpy.data.objects['Attachment.RIG'].data.edit_bones['AttachmentRoot']
                    attachmentBone.tail = (selBone.tail[0], selBone.tail[1], selBone.tail[2])
                    attachmentBone.roll = selBone.roll

                    attachmentBoneNode = bpy.data.objects['Attachment.RIG'].data.edit_bones['AttachmentNode']
                    attachmentBoneNode.tail = (selBone.tail[0], selBone.tail[1], selBone.tail[2])
                    attachmentBoneNode.roll = selBone.roll
                
                    bpy.ops.object.mode_set(mode='OBJECT')

                    if not str(myArmature.users_collection[0].name) == "ATTACHMENT_EXPORT":
                        bpy.data.collections['ATTACHMENT_EXPORT'].objects.link(myArmature)
                        for myMesh in myMeshes:
                            bpy.data.collections['ATTACHMENT_EXPORT'].objects.link(myMesh)
                            myMesh.users_collection[-1].objects.unlink(myMesh)
                        myArmature.users_collection[-1].objects.unlink(myArmature)

                    bpy.ops.object.select_all(action='DESELECT')

                    for each in myArmature.users_collection[0].all_objects:
                        if each.name == "Attachment.RIG":
                            each.data.bones[-1].name = each.data.bones[-1].name + "[" + boneToBind.name + "]"
                            bpy.data.objects[each.name].select_set(True)
                            bpy.context.view_layer.objects.active = bpy.data.objects[str(each.name)]
                        if each.name == myArmature.name:
                            bpy.data.objects[each.name].select_set(True)
                            bpy.context.view_layer.objects.active = bpy.data.objects[str(each.name)]

                    bpy.ops.object.join()

                    for bone in armature.bones:
                        if "AttachmentNode" in bone.name:
                            attachNode = bone

                    bpy.ops.object.mode_set(mode='EDIT')
                    myArmature.data.edit_bones[myArmature.data.bones[0].name].parent = myArmature.data.edit_bones[attachNode.name]
                    bpy.ops.object.mode_set(mode='OBJECT')
                    bpy.ops.object.select_all(action='DESELECT')
                    

        return {'FINISHED'}




class IMVUTOOL_PT_clothing_panel(bpy.types.Panel): #CLOTHING PANEL
    bl_label = "Clothing Tool"
    bl_idname = "IMVUTOOL_PT_clothing_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "IMVU Studio Toolkit"
    bl_options = {'DEFAULT_CLOSED'}
 
    def draw(self, context):
        layout = self.layout
        scene = context.scene
        imvutool = scene.imvu_tool

        ButtonActive = False
        someExist = False

        
        for col in bpy.context.view_layer.layer_collection.children:
            if col.name == "Clothing_Scene":
                ButtonActive = True

        disabledCollections = ["ROOM_EXPORT", "FURNITURE_EXPORT", "Attachment_Scene", "Animation_Scene", "Head_Scene"]
        for each in disabledCollections:
            for col in bpy.context.view_layer.layer_collection.children:
                if col.name == each:
                    someExist = True

        
        isPaintMode = False
        isPoseMode = False
        sel = bpy.context.selected_objects
        if len(sel) > 0:
            if bpy.context.object.mode == "WEIGHT_PAINT":
                isPaintMode = True
            if bpy.context.object.mode == "POSE":
                isPoseMode = True


        boxAppend = layout.box()
        boxAppend.enabled = not someExist

        rowAppend = boxAppend.row()
        rowAppend.enabled = not ButtonActive
        rowAppend.operator("imvutool.clothing_operator", icon= "MATCLOTH")

        if(ButtonActive):
            boxMain = layout.box()
            boxMain.enabled = ButtonActive
            rowGender = boxMain.row()
            rowGender.prop(imvutool, "clothing_gender", expand= False, text="Gender")

            rowBind = boxMain.row()
            rowBind.operator("imvutool.clothing_bind_operator")
            

            rowPaintPose = boxMain.row()
            split = rowPaintPose.split(factor=0.5)
            colPaint = split.column()
            colPose = split.column()
            colPaint.alert = isPaintMode
            colPose.alert = isPoseMode
            colPaint.operator("imvutool.clothing_paint_operator")
            colPose.operator("imvutool.clothing_pose_operator")

            rowResetPose = boxMain.row()
            rowResetPose.operator("imvutool.clothing_reset_pose_operator")

            rowLimit = boxMain.row()
            rowLimit.operator("imvutool.clothing_limit_operator")

            boxMCG = layout.box()
            rowShowRef = boxMCG.row()
            rowShowRef.prop(imvutool, "showMCG", text= "Show MCG Reference")
            rowSlider = boxMCG.row()
            rowSlider.prop(imvutool, "MCGSlider", slider=True)
            rowInfo = boxMCG.row()
            rowInfo.operator("wm.url_open", text="More MCG Info", icon= "QUESTION").url = "https://create.imvu.com/articles/studio/understanding-manipulated-mcg-products/"

class IMVUTOOL_OT_clothing_op(bpy.types.Operator): #Append Clothing File
    bl_label = "Append Clothing File"
    bl_idname = "imvutool.clothing_operator"
    bl_description = "Append Clothing File \nTo export body parts, drag them out of their respective collection, and into the 'CLOTHING_EXPORT' collection."
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):

        if not checkMega():
            bpy.ops.imvutool.megascene('INVOKE_DEFAULT')
            return{'FINISHED'}

        bpy.context.space_data.shading.type = 'MATERIAL'

        file_path = GetPathToFile(self, "IMVUMegaScene.blend")

        if file_path:        
            inner_path = 'Collection'
            object_name = "Clothing_Scene"

            DelInitialCollection()

            bpy.ops.wm.append(
                            filepath=os.path.join(file_path, inner_path, object_name),
                            directory=os.path.join(file_path, inner_path),
                            filename=object_name
                            )
            setMaleFemaleClothing(self, context)
            
            for each in bpy.data.collections:
                if "MCG" in each.name:
                    femaleMCG = each
                    for obj in femaleMCG.objects:
                        obj.hide_set(True)

            bpy.ops.object.select_all(action='DESELECT')

        return {'FINISHED'}

class IMVUTOOL_OT_clothing_op2(bpy.types.Operator): #Bind to Armature
    bl_label = "Bind to Armature"
    bl_idname = "imvutool.clothing_bind_operator"
    bl_description = "Weight the Selected Object to the armature"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        self.master_collection = bpy.context.scene.collection
        
        obj = bpy.context.selected_objects
        if len(obj) == 0:
            self.report({"WARNING"}, "Please select an object to attach!")
        elif not obj[0].type == "MESH":
            self.report({"WARNING"}, "Please select a mesh!")
        else:
            for each in range(len(obj)):
                if not str(obj[each].users_collection[0].name) == "CLOTHING_EXPORT":
                    for collection in obj[each].users_collection:
                        collection.objects.unlink(obj[each])
                    bpy.data.collections['CLOTHING_EXPORT'].objects.link(obj[each])

                bpy.data.objects[obj[each].name].select_set(True)
                bpy.data.objects['Clothing_Avatar_Armature'].select_set(True)
                bpy.context.view_layer.objects.active = bpy.data.objects['Clothing_Avatar_Armature']
                bpy.ops.object.parent_set(type='ARMATURE_AUTO')

        return {'FINISHED'}

class IMVUTOOL_OT_clothing_op3(bpy.types.Operator): #Paint Weights
    bl_label = "Paint Weights"
    bl_idname = "imvutool.clothing_paint_operator"
    bl_description = "Adjust the bone weighting"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        self.master_collection = bpy.context.scene.collection

        obj = bpy.context.selected_objects
        if bpy.context.object.mode == "WEIGHT_PAINT":
            bpy.ops.object.mode_set(mode='OBJECT')
        else:

            if len(obj) == 0:
                self.report({"WARNING"}, "No Clothing Selected!")
            elif len(obj) > 1:
                self.report({"WARNING"}, "Too Many Meshes Selected!")
            elif not obj[0].type == "MESH":
                self.report({"WARNING"}, "Selection Isn't a Mesh")
            else:
                bpy.ops.object.mode_set(mode='OBJECT')

                bpy.ops.object.select_all(action='DESELECT')
                
                bpy.data.objects[obj[0].name].select_set(True)
                bpy.ops.object.mode_set(mode='WEIGHT_PAINT')
            
            for area in context.screen.areas:
                if area.type == 'PROPERTIES':
                    area.spaces[0].context = "DATA"

        return {'FINISHED'}

class IMVUTOOL_OT_clothing_op4(bpy.types.Operator): #Pose Mode
    bl_label = "Pose"
    bl_idname = "imvutool.clothing_pose_operator"
    bl_description = "Pose the Character"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        
        self.master_collection = bpy.context.scene.collection
        
        if bpy.context.object.mode == "POSE":
            bpy.ops.object.mode_set(mode='OBJECT')
            bpy.ops.object.select_all(action='DESELECT')
        else:
            obj = bpy.context.selected_objects
            if not len(obj) == 0:
                bpy.ops.object.mode_set(mode='OBJECT')
                bpy.ops.object.select_all(action='DESELECT')

            bpy.data.objects["Clothing_Avatar_Armature"].select_set(True)
            bpy.context.view_layer.objects.active = bpy.data.objects['Clothing_Avatar_Armature']
            bpy.ops.object.mode_set(mode='POSE')

        return {'FINISHED'}

class IMVUTOOL_OT_clothing_op5(bpy.types.Operator): #Reset Pose
    bl_label = "Reset Pose"
    bl_idname = "imvutool.clothing_reset_pose_operator"
    bl_description = "Reset the pose to the original stance"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        if not bpy.context.object.mode == "OBJECT":
            bpy.ops.object.mode_set(mode='OBJECT')

        bpy.ops.object.select_all(action='DESELECT')
        bpy.data.objects["Clothing_Avatar_Armature"].select_set(True)
        bpy.context.view_layer.objects.active = bpy.data.objects["Clothing_Avatar_Armature"]

        bpy.ops.object.mode_set(mode='POSE')
        bpy.ops.pose.select_all(action='SELECT')
        bpy.ops.pose.user_transforms_clear()
        bpy.ops.object.mode_set(mode='OBJECT')
        bpy.ops.object.select_all(action='DESELECT')

        return {'FINISHED'}

class IMVUTOOL_OT_clothing_op6(bpy.types.Operator): #Limit Bones
    bl_label = "Limit Bones"
    bl_idname = "imvutool.clothing_limit_operator"
    bl_description = "Limit the number of bones per vertex to 6"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        
        if len(bpy.data.collections['CLOTHING_EXPORT'].all_objects) < 1:
            self.report({"WARNING"}, "No Clothing Found!")
        else:
            if len(bpy.data.collections['CLOTHING_EXPORT'].all_objects) == 0:
                self.report({"WARNING"}, "No Clothing Found!")
            else:
                bpy.ops.object.mode_set(mode='OBJECT')
                bpy.ops.object.select_all(action='DESELECT')
                
                for each in range(len(bpy.data.collections['CLOTHING_EXPORT'].all_objects)):
                    bpy.data.objects[(bpy.data.collections['CLOTHING_EXPORT'].all_objects)[each].name].select_set(True)
                    bpy.context.view_layer.objects.active = (bpy.data.collections['CLOTHING_EXPORT'].all_objects)[each]
                    bpy.ops.object.mode_set(mode='WEIGHT_PAINT')

                    bpy.ops.object.vertex_group_limit_total(limit=6)

                    bpy.ops.object.mode_set(mode='OBJECT')
                    bpy.ops.object.select_all(action='DESELECT')

        return {'FINISHED'}




class IMVUTOOL_PT_animation_panel(bpy.types.Panel): #ANIMATION PANEL
    bl_label = "Animation Tool"
    bl_idname = "IMVUTOOL_PT_animation_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "IMVU Studio Toolkit"
    bl_options = {'DEFAULT_CLOSED'}
 
    def draw(self, context):
        layout = self.layout
        scene = context.scene
        imvutool = scene.imvu_tool

        ButtonActive = False
        someExist = False


        for col in bpy.context.view_layer.layer_collection.children:
            if col.name == "Animation_Scene":
                ButtonActive = True

        disabledCollections = ["Attachment_Scene", "Head_Scene"]
        for each in disabledCollections:
            for col in bpy.context.view_layer.layer_collection.children:
                if col.name == each:
                    someExist = True
            
        isPaintMode = False
        sel = bpy.context.selected_objects
        if len(sel) > 0:
            if bpy.context.object.mode == "WEIGHT_PAINT":
                isPaintMode = True

        isKeying = bpy.context.scene.tool_settings.use_keyframe_insert_auto

        box_append = layout.box()
        box_append.enabled = not someExist

        row_append = box_append.row()
        row_append.operator("imvutool.animation_operator", icon= "ARMATURE_DATA")

        isTwoAvatars = False
        for col in bpy.data.collections:
            if "Animation_Scene." in col.name:
                isTwoAvatars = True

        if(ButtonActive):
            box_exports = layout.box()
            box_exports.enabled = ButtonActive
            row_make_pose = box_exports.row()
            row_make_pose.prop(imvutool, "isPose", text= "Make Pose")
            row_all_bones = box_exports.row()
            row_all_bones.prop(imvutool, "exportAll", text= "Export All Bones")
            row_export_clothing = box_exports.row()
            row_export_clothing.prop(imvutool, "exportClothing", text= "Export Clothing")
            row_morph = box_exports.row()
            row_morph.prop(imvutool, "enableMorph", text= "Morph Controls")

            box_anim_length = layout.box()
            box_anim_length.enabled = ButtonActive and not imvutool.isPose
            row_anim_length = box_anim_length.row()
            row_anim_length.prop(imvutool, "animationLen")


            box_ikfk = layout.box()
            box_ikfk.enabled = ButtonActive
            row_ikfk_label = box_ikfk.row()
            row_ikfk_label.alignment="CENTER"
            row_ikfk_label.label(text= "= IK", icon= "CHECKBOX_HLT")
            row_ikfk_label.label(text= "= FK", icon= "CHECKBOX_DEHLT")
            # row4.label(text= "IK (FK when disabled)")
            row_ikfk_arms = box_ikfk.row()
            row_ikfk_arms.prop(imvutool, "rightArmIK", text= "Right Arm")
            row_ikfk_arms.prop(imvutool, "leftArmIK", text= "Left Arm")
            row_ikfk_legs = box_ikfk.row()
            row_ikfk_legs.prop(imvutool, "rightLegIK", text= "Right Leg")
            row_ikfk_legs.prop(imvutool, "leftLegIK", text= "Left Leg")

            box_rotiso = layout.box()
            box_rotiso.enabled = ButtonActive
            row_rotiso_label = box_rotiso.row()
            row_rotiso_label.alignment="CENTER"
            row_rotiso_label.label(text= "Rotation Isolation")
            row_rotiso_arms = box_rotiso.row()
            c_rotiso_arm_l = row_rotiso_arms.column()
            c_rotiso_arm_l.enabled = not imvutool.rightArmIK
            c_rotiso_arm_r = row_rotiso_arms.column()
            c_rotiso_arm_r.enabled = not imvutool.leftArmIK
            c_rotiso_arm_l.prop(imvutool, "rightArmIso", text= "Right Arm")
            c_rotiso_arm_r.prop(imvutool, "leftArmIso", text= "Left Arm")
            row_rotiso_legs = box_rotiso.row()
            c_rotiso_leg_l = row_rotiso_legs.column()
            c_rotiso_leg_l.enabled = not imvutool.rightLegIK
            c_rotiso_leg_r = row_rotiso_legs.column()
            c_rotiso_leg_r.enabled = not imvutool.leftLegIK
            c_rotiso_leg_l.prop(imvutool, "rightLegIso", text= "Right Leg")
            c_rotiso_leg_r.prop(imvutool, "leftLegIso", text= "Left Leg")

            box_key_pose = layout.box()
            box_key_pose.enabled = ButtonActive
            row_rotiso_legs = box_key_pose.row()

            split_key = row_rotiso_legs.split(factor=0.5)
            c_key_add = split_key.column()
            c_key_auto = split_key.column()
            c_key_auto.alert = isKeying
            c_key_add.operator("imvutool.animation_key_operator", icon= "HANDLETYPE_FREE_VEC")
            c_key_auto.operator("imvutool.animation_auto_operator", icon= "REC")

            row_zero = box_key_pose.row()
            row_zero.operator("imvutool.animation_reset_operator", icon= "COMMUNITY")
            row_zero.operator("imvutool.animation_reset_bone_operator", icon= "GROUP_BONE")
            
            box_clothing = layout.box()
            box_clothing.enabled = ButtonActive and not isTwoAvatars
            row_clothinglabel = box_clothing.row()
            row_clothinglabel.alignment="CENTER"
            row_clothinglabel.label(text= "Clothing Settings")
            row_prep = box_clothing.row()
            row_prep.alert = bpy.data.objects['Anim'].data.pose_position == 'REST'
            row_prep.operator("imvutool.prepare_clothing", icon= "OUTLINER_OB_ARMATURE")
            row_bind = box_clothing.row()
            row_bind.operator("imvutool.bind_clothing", icon= "MATCLOTH")
            row_paint = box_clothing.row()
            row_paint.alert = isPaintMode
            row_paint.operator("imvutool.paint_anim_clothing", icon= "BRUSH_DATA")
            row_limit_bones = box_clothing.row()
            row_limit_bones.operator("imvutool.limit_anim_clothing", icon= "BONE_DATA")

class IMVUTOOL_OT_animation_op(bpy.types.Operator): #Append Animation File
    bl_label = "Append Animation File"
    bl_idname = "imvutool.animation_operator"
    bl_description = "Append Animation File"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool

        bpy.context.view_layer.active_layer_collection = bpy.context.view_layer.layer_collection

        if not checkMega():
            bpy.ops.imvutool.megascene('INVOKE_DEFAULT')
            return{'FINISHED'}

        file_path = GetPathToFile(self, "IMVUMegaScene.blend")
        
        if file_path:
            inner_path = 'Collection'
            object_name = "Animation_Scene"

            bpy.context.space_data.shading.type = 'MATERIAL'
            bpy.context.scene.render.fps = 30

            DelInitialCollection()

            bpy.ops.wm.append(
                            filepath=os.path.join(file_path, inner_path, object_name),
                            directory=os.path.join(file_path, inner_path),
                            filename=object_name
                            )

            bpy.context.space_data.overlay.show_relationship_lines = False

            for each in bpy.data.collections:
                if "ProxyMeshBones" in each.name:
                    each.hide_viewport = True
            # proxyBones = bpy.data.collections["ProxyMeshBones"]
            # proxyBones.hide_viewport = True

            bpy.context.scene.frame_end = imvutool.animationLen

            bpy.context.view_layer.objects.active = bpy.data.objects['Control_Armature']
            bpy.ops.object.mode_set(mode='POSE')

            isAction = False
            start_areas = context.screen.areas[:]
            
            for area in context.screen.areas:
                if area.type == 'DOPESHEET_EDITOR':
                    if area.spaces[0].ui_mode == 'ACTION':
                        isAction = True

            if not isAction:
                bpy.ops.screen.area_split(direction='HORIZONTAL', factor=0.2)
                for area in context.screen.areas:
                    if area not in start_areas:
                        area.type = 'DOPESHEET_EDITOR'
                        area.spaces[0].ui_mode = 'ACTION'
                        
            bpy.ops.object.mode_set(mode='OBJECT')
            bpy.ops.object.select_all(action='DESELECT')

        return {'FINISHED'}

class IMVUTOOL_OT_animation_op2(bpy.types.Operator): #Key Bone
    bl_label = "Add Key"
    bl_idname = "imvutool.animation_key_operator"
    bl_description = "Add a keyframe to the selected bone"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):

        bpy.ops.anim.keyframe_insert_menu(type='BUILTIN_KSI_LocRot')
        
        return {'FINISHED'}

class IMVUTOOL_OT_animation_op3(bpy.types.Operator): #Turn Auto Key On
    bl_label = "Auto Key"
    bl_idname = "imvutool.animation_auto_operator"
    bl_description = "Turn on auto keyframe"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        isAuto = not bpy.context.scene.tool_settings.use_keyframe_insert_auto
        bpy.context.scene.tool_settings.use_keyframe_insert_auto = isAuto
        bpy.context.scene.tool_settings.auto_keying_mode = 'ADD_REPLACE_KEYS'

        return {'FINISHED'}

class IMVUTOOL_OT_animation_op4(bpy.types.Operator): #Reset Pose
    bl_label = "Zero Pose"
    bl_idname = "imvutool.animation_reset_operator"
    bl_description = "Reset all bones to their original position"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        bpy.ops.object.mode_set(mode='POSE')
        bpy.ops.pose.select_all(action='SELECT')
        bpy.ops.pose.rot_clear()
        bpy.ops.pose.loc_clear()
        bpy.ops.pose.scale_clear()

        return {'FINISHED'}

class IMVUTOOL_OT_animation_op5(bpy.types.Operator): #Reset Single Bone Pose
    bl_label = "Zero Bone"
    bl_idname = "imvutool.animation_reset_bone_operator"
    bl_description = "Reset selected bones to their original position"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        bpy.ops.pose.rot_clear()
        bpy.ops.pose.loc_clear()
        bpy.ops.pose.scale_clear()

        return {'FINISHED'}

class IMVUTOOL_OT_animation_op6(bpy.types.Operator): #Prepare the avatar for clothing binding
    bl_label = "Prep Cloth"
    bl_idname = "imvutool.prepare_clothing"
    bl_description = "Set the avatar to T-Pose to make accurate skin binding"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        for col in bpy.context.view_layer.layer_collection.children:
            if "Animation_Scene" in col.name:
                for subCol in col.children:
                    if("ANIMATION_EXPORT" in subCol.name):
                        bpy.context.view_layer.active_layer_collection = subCol
                        for obj in bpy.data.collections[subCol.name].all_objects:
                            if "Anim" in obj.name:
                                obj.select_set(True)
                                if (bpy.data.objects['Anim'].data.pose_position == 'REST'):
                                    bpy.data.objects['Anim'].data.pose_position = 'POSE'
                                elif (bpy.data.objects['Anim'].data.pose_position == 'POSE'):
                                    bpy.data.objects['Anim'].data.pose_position = 'REST'
                                
        bpy.ops.object.select_all(action='DESELECT')
        

        return {'FINISHED'}

class IMVUTOOL_OT_animation_op7(bpy.types.Operator): #Bind Clothing
    bl_label = "Bind Cloth"
    bl_idname = "imvutool.bind_clothing"
    bl_description = "Bind the selected mesh to the avatar"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        self.master_collection = bpy.context.scene.collection
        
        obj = bpy.context.selected_objects
        if len(obj) == 0:
            self.report({"WARNING"}, "Please select an object to attach!")
        elif not obj[0].type == "MESH":
            self.report({"WARNING"}, "Please select a mesh!")
        else:
            for each in range(len(obj)):
                if not str(obj[each].users_collection[0].name) == "Skeleton":
                    for collection in obj[each].users_collection:
                        collection.objects.unlink(obj[each])
                    bpy.data.collections['Skeleton'].objects.link(obj[each])

                bpy.data.objects[obj[each].name].select_set(True)
                bpy.data.objects['Anim'].select_set(True)
                bpy.context.view_layer.objects.active = bpy.data.objects['Anim']
                bpy.ops.object.parent_set(type='ARMATURE_AUTO')

        return {'FINISHED'}

class IMVUTOOL_OT_animation_op8(bpy.types.Operator): #Paint Clothing
    bl_label = "Paint Weights"
    bl_idname = "imvutool.paint_anim_clothing"
    bl_description = "Adjust the bone weighting"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        self.master_collection = bpy.context.scene.collection

        obj = bpy.context.selected_objects
        if bpy.context.object.mode == "WEIGHT_PAINT":
            bpy.ops.object.mode_set(mode='OBJECT')
        else:

            if len(obj) == 0:
                self.report({"WARNING"}, "No Clothing Selected!")
            elif len(obj) > 1:
                self.report({"WARNING"}, "Too Many Meshes Selected!")
            elif not obj[0].type == "MESH":
                self.report({"WARNING"}, "Selection Isn't a Mesh")
            else:
                bpy.ops.object.mode_set(mode='OBJECT')

                bpy.ops.object.select_all(action='DESELECT')
                
                bpy.data.objects[obj[0].name].select_set(True)
                bpy.ops.object.mode_set(mode='WEIGHT_PAINT')
            
            for area in context.screen.areas:
                if area.type == 'PROPERTIES':
                    area.spaces[0].context = "DATA"

        return {'FINISHED'}

class IMVUTOOL_OT_animation_op9(bpy.types.Operator): #Limit Bones
    bl_label = "Limit Bone Weights"
    bl_idname = "imvutool.limit_anim_clothing"
    bl_description = "Limit how many bones affect each vertex"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        children = [] 
        for ob in bpy.data.objects: 
            if ob.parent == bpy.data.objects['Anim']: 
                children.append(ob) 
                
        if len(children) < 1:
            self.report({"WARNING"}, "No Clothing Found!")
        else:
            bpy.ops.object.mode_set(mode='OBJECT')
            bpy.ops.object.select_all(action='DESELECT')
            
            for each in range(len(children)):
                bpy.data.objects[(children)[each].name].select_set(True)
                bpy.context.view_layer.objects.active = (children)[each]
                bpy.ops.object.mode_set(mode='WEIGHT_PAINT')

                bpy.ops.object.vertex_group_limit_total(limit=6)

                bpy.ops.object.mode_set(mode='OBJECT')
                bpy.ops.object.select_all(action='DESELECT')


        return {'FINISHED'}




class IMVUTOOL_PT_head_panel(bpy.types.Panel): #HEAD PANEL
    bl_label = "Head Tool"
    bl_idname = "IMVUTOOL_PT_head_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "IMVU Studio Toolkit"
    bl_options = {'DEFAULT_CLOSED'}
 
    def draw(self, context):
        layout = self.layout
        scene = context.scene
        imvutool = scene.imvu_tool

        ButtonActive = False
        someExist = False
        isGridSetup = False


        for col in bpy.context.view_layer.layer_collection.children:
            if col.name == "Head_Scene":
                ButtonActive = True
                
                if len(bpy.data.objects['Head_Avatar_Armature'].children) > 0:
                    isGridSetup = True
                

        disabledCollections = ["ROOM_EXPORT", "Attachment_Scene", "FURNITURE_EXPORT", "Clothing_Scene", "Animation_Scene"]
        for each in disabledCollections:
            for col in bpy.context.view_layer.layer_collection.children:
                if col.name == each:
                    someExist = True

        box_append = layout.box()
        box_append.enabled = not someExist

        row_append = box_append.row()
        row_append.enabled = not ButtonActive
        row_append.operator("imvutool.head_operator", icon= "COMMUNITY")

        if(ButtonActive):
            box_Setup = layout.box()
            box_Setup.enabled = ButtonActive
            row_radio = box_Setup.row()
            row_radio.prop(imvutool, "head_gender", expand= True)
            row_create_grid = box_Setup.row()
            row_create_grid.enabled = not isGridSetup
            row_create_grid.operator("imvutool.create_grid", icon= "MESH_GRID")

class IMVUTOOL_OT_head_op(bpy.types.Operator): #Append Head File
    bl_label = "Append Head File"
    bl_idname = "imvutool.head_operator"
    bl_description = "Append Head File"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool

        bpy.context.view_layer.active_layer_collection = bpy.context.view_layer.layer_collection

        if not checkMega():
            bpy.ops.imvutool.megascene('INVOKE_DEFAULT')
            return{'FINISHED'}

        file_path = GetPathToFile(self, "IMVUMegaScene.blend")
        
        if file_path:
            inner_path = 'Collection'
            object_name = "Head_Scene"

            DelInitialCollection()

            bpy.ops.wm.append(
                            filepath=os.path.join(file_path, inner_path, object_name),
                            directory=os.path.join(file_path, inner_path),
                            filename=object_name
                            )
            
            setMaleFemaleHead(self, context)

            # bpy.ops.object.mode_set(mode='OBJECT')
            # bpy.ops.object.select_all(action='DESELECT')

        return {'FINISHED'}

class IMVUTOOL_OT_head_op2(bpy.types.Operator): #Create Grid
    bl_label = "Create Grid"
    bl_idname = "imvutool.create_grid"
    bl_description = "Makes copies of the head to setup blendshapes.\nMake sure your head is done before this step, there is no changing after the grid has been made"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
            
        scene = context.scene
        imvutool = scene.imvu_tool

        self.master_collection = bpy.context.scene.collection
        
        obj = bpy.context.selected_objects

        if len(obj) == 0:
            self.report({"WARNING"}, "Please select your head object!")
        elif not obj[0].type == "MESH":
            self.report({"WARNING"}, "Please select a mesh!")
        else:
            bpy.ops.ed.undo_push()
            origHead = bpy.context.selected_objects[0]
            
            # Apply Tranforms
            mb = origHead.matrix_basis
            if hasattr(origHead.data, "transform"):
                origHead.data.transform(mb)
            for c in origHead.children:
                c.matrix_local = mb @ c.matrix_local
            origHead.matrix_basis.identity()


            for each in range(len(obj)):
                if not str(obj[each].users_collection[0].name) == "HEAD_EXPORT":
                    for collection in obj[each].users_collection:
                        collection.objects.unlink(obj[each])
                    bpy.data.collections['HEAD_EXPORT'].objects.link(obj[each])

            bpy.context.scene.cursor.location = (0.006307, 0.343104, 9.67747)
            bpy.ops.object.origin_set(type='ORIGIN_CURSOR')  
            bpy.context.scene.cursor.location = (0, 0, 0)

            
            for each in bpy.data.collections:
                if "Ref" in each.name:
                    for obj in each.objects:
                        origHead.select_set(True)
                        bpy.ops.object.duplicate()
                        dupHead = bpy.context.selected_objects[0]
                        dupHead.location = (obj.location[0]+3, obj.location[1], obj.location[2]-9.67747)
                        dupHead.name = (obj.name[4:])
                        dupHead.parent = origHead
                        bpy.ops.object.select_all(action='DESELECT')


            origHead.select_set(True)
            bpy.data.objects['Head_Avatar_Armature'].select_set(True)
            bpy.context.view_layer.objects.active = bpy.data.objects['Head_Avatar_Armature']
            mod = origHead.modifiers.new("Armature", 'ARMATURE')
            mod.object = bpy.data.objects["Head_Avatar_Armature"]
            origHead.vertex_groups.new( name = 'Head' )
            if imvutool.head_gender == "Male":
                origHead.vertex_groups.new( name = 'Neck03' )
            if imvutool.head_gender == "Female":
                origHead.vertex_groups.new( name = 'Neck04' )
            origHead.parent = bpy.data.objects['Head_Avatar_Armature']





        return {'FINISHED'}




class IMVUTOOL_PT_export_panel(bpy.types.Panel): #EXPORT PANEL
    bl_label = "Export Tool"
    bl_idname = "IMVUTOOL_PT_export_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "IMVU Studio Toolkit"
 
    def draw(self, context):
        layout = self.layout
        
        global needUpdate
        global isDevVersion

        updateIndex = 0
        if needUpdate:
            updateIndex = 1
        elif isDevVersion:
            updateIndex = 2

        row = layout.row()
        row.operator("imvutool.export_operator", icon= "EXPORT")

        row2 = layout.row()
        row2.operator("imvutool.export_open_dir", text="Open Export Directory", icon= "FILE_FOLDER")

        row3 = layout.row()
        row3.operator("wm.url_open", text="Help", icon= "HELP").url = "https://create.imvu.com/articles/studio/toolkit-blender/"

        versionNum = str(list(bl_info.get("version"))[0]) + "." + str(list(bl_info.get("version"))[1]) + "." + str(list(bl_info.get("version"))[2])
        updateText = [str(versionNum), "UPDATE AVAILABLE!", "DEV VERSION"]
        updateIcon = ["INFO", "ERROR", "MODIFIER"]

        row4 = layout.row()
        row4.alignment="CENTER"
        box1 = row4.box()
        box1.alignment="CENTER"
        box1.enabled = needUpdate or isDevVersion
        box1.alert = needUpdate
        box1.operator("wm.url_open", text=updateText[updateIndex], icon=updateIcon[updateIndex]).url = "https://create.imvu.com/articles/studio/toolkit/#blender"
        
        if needUpdate or isDevVersion:
            row5 = layout.row()
            row5.alignment="RIGHT"
            row5.enabled = False
            row5.label(text=versionNum)

        errorTest = ""

        global errorStr
        if not checkMega():
            errorHandling("Wrong Scene", row, row2, row4, layout)

        if (bpy.path.basename(bpy.context.blend_data.filepath) == ""):
            errorHandling("File Not Saved", row, row2, row4, layout)

class IMVUTOOL_OT_export_op1(bpy.types.Operator): #Open Export Directory
    bl_label = "Export Directory"
    bl_idname = "imvutool.export_open_dir"
    bl_description = "Opens the export location of the file"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):

        if(bpy.data.is_saved):
            filepath = bpy.data.filepath
            # self.report({"WARNING"}, str(platform.system()))
            if platform.system() == "Windows":
                os.startfile(os.path.dirname(filepath))
            elif platform.system() == "Darwin":
                subprocess.call(["open", "-R", filepath])
        else:
            self.report({"WARNING"}, "You Must Save Your File First!")

        return {'FINISHED'}

class IMVUTOOL_OT_export_op(bpy.types.Operator): #Export
    bl_label = "Export"
    bl_idname = "imvutool.export_operator"
    bl_description = "Export your creation!"
    
    def execute(self, context):
        scene = context.scene
        imvutool = scene.imvu_tool

        exportName = bpy.path.basename(bpy.context.blend_data.filepath)

        exported = False

        if(exportName == ""):
            bpy.ops.imvutool.export_error('INVOKE_DEFAULT')
        else:
            for col in bpy.context.view_layer.layer_collection.children:
                if "Animation_Scene" in col.name: #Animation Export Setup
                    if len(bpy.context.view_layer.layer_collection.children) < 1:
                        self.report({"WARNING"}, "No Animation Found!")
                        
                    if "." in col.name:
                        animNum = "." + str(col.name).split(".")[-1]
                    else:
                        animNum = ""

                    bpy.ops.object.mode_set(mode='OBJECT')
                    bpy.ops.object.select_all(action='DESELECT')
                    
                    anim = bpy.context.scene.objects["Control_Armature" + animNum]
                    context.view_layer.objects.active = anim
                    sel = bpy.context.object

                    myAnim = bpy.data.objects['Anim' + animNum]

                    if imvutool.isPose:
                        bpy.ops.object.mode_set(mode='POSE')
                        bpy.ops.pose.select_all(action='SELECT')
                        bpy.context.scene.frame_set(1)
                        bpy.ops.pose.copy()

                        bpy.context.scene.frame_set(5)
                        bpy.ops.pose.paste()

                        bpy.context.scene.frame_set(10)
                        bpy.ops.pose.rot_clear()
                        bpy.ops.pose.loc_clear()
                        bpy.ops.pose.scale_clear()
                        

                    if(sel.animation_data.action == None):
                        self.report({"WARNING"}, "No Animation Found!")
                    else:

                        bpy.data.actions[str(myAnim.animation_data.action.name)].name = ("-" + str(sel.animation_data.action.name))
                        
                        bpy.context.view_layer.objects.active = bpy.data.objects['Anim' + animNum]

                        bpy.context.scene.frame_set(0)
                        myAnim.keyframe_insert(data_path = 'scale')
                        myAnim.keyframe_insert(data_path = 'location')
                        myAnim.keyframe_insert(data_path = 'rotation_euler')

                        bpy.context.scene.frame_set(imvutool.animationLen)
                        myAnim.keyframe_insert(data_path = 'location')
                        myAnim.keyframe_insert(data_path = 'rotation_euler')
                        myAnim.keyframe_insert(data_path = 'scale')
                        
                        bpy.context.scene.frame_set(1)

                        bpy.ops.object.mode_set(mode='OBJECT')
                        bpy.ops.object.select_all(action='DESELECT')

                        for obj in bpy.data.collections['ANIMATION_EXPORT' + animNum].all_objects:
                            obj.select_set(True)



            for col in bpy.context.view_layer.layer_collection.children:
                if col.name == "ROOM_EXPORT": #Room Export
                    exported = True
                    if len(bpy.context.view_layer.layer_collection.children) < 1:
                        self.report({"WARNING"}, "No Room Found!")
                        
                    for col in bpy.context.view_layer.layer_collection.children:
                        if col.name == "ROOM_EXPORT":
                            
                            if(checkValidExport(self, context, "Room")):
                                bpy.ops.object.mode_set(mode= 'OBJECT')
                                bpy.ops.object.select_all(action='DESELECT')
                                bpy.context.view_layer.active_layer_collection = col
                                bpy.ops.object.select_all(action='DESELECT')

                                bpy.ops.export_scene.fbx(
                                    filepath= bpy.path.abspath("//" + "Room_" + str(exportName.split('.')[0]) + ".fbx"),
                                    use_active_collection= True
                                    )
                                self.report({"INFO"}, "Room Exported as " + "Room_" + str(exportName.split('.')[0]) + "!")

                if col.name == "FURNITURE_EXPORT": #Furniture Export
                    exported = True
                    if len(bpy.context.view_layer.layer_collection.children) < 1:
                        self.report({"WARNING"}, "No Furniture Found!")
                        
                    for col in bpy.context.view_layer.layer_collection.children:
                        if col.name == "FURNITURE_EXPORT":
                            bpy.context.view_layer.active_layer_collection = col
                            numSeats = 0
                            for o in bpy.context.scene.objects:
                                if "seat" in o.name:
                                    numSeats += 1
                            if numSeats < 0:
                                self.report({"WARNING"}, "Not Enough Seats! You need at least 6.")
                            else:
                                bpy.ops.export_scene.fbx(
                                    filepath= bpy.path.abspath("//" + "Furn_" + str(exportName.split('.')[0]) + ".fbx"),
                                    use_active_collection= True
                                    )

                                self.report({"INFO"}, "Furniture Exported as " + "Furn_" + str(exportName.split('.')[0]) + "!")

                if col.name == "Attachment_Scene": #Attachment Export
                    exported = True
                    bpy.ops.object.mode_set(mode='OBJECT')
                    if len(bpy.context.view_layer.layer_collection.children) < 1:
                        self.report({"WARNING"}, "No Attachments Found!")
                        
                    else:
                        bpy.ops.object.mode_set(mode= 'OBJECT')
                        bpy.ops.object.select_all(action='DESELECT')

                        for obj in bpy.data.collections['ATTACHMENT_EXPORT'].all_objects:
                            obj.select_set(True)

                        bpy.ops.export_scene.fbx(
                            filepath= bpy.path.abspath("//" + "Attachment_" + str(exportName.split('.')[0]) + ".fbx"),
                            use_selection= True, use_active_collection= False, primary_bone_axis= "X", secondary_bone_axis= "-Y", bake_anim_use_nla_strips= False, bake_anim_force_startend_keying= False
                            )
                            
                        self.report({"INFO"}, "Attachment Exported as " + "Attachment_" + str(exportName.split('.')[0]) + "!")
                            
                if col.name == "Clothing_Scene": #Clothing Export
                    exported = True
                    error = False
                    if len(bpy.context.view_layer.layer_collection.children) < 1:
                        self.report({"WARNING"}, "No Clothing Found!")
                    else:
                        for obj in bpy.data.collections["CLOTHING_EXPORT"].objects:
                            mesh_name = bpy.data.objects[obj.name].data.name
                            listbones = {}
                            b=0

                            for modifiers in bpy.data.objects[obj.name].modifiers:
                                if modifiers.type == 'ARMATURE':
                                    data = bpy.data.objects[modifiers.object.name].data.name
                                    for bones in bpy.data.armatures[data].bones:
                                        listbones[bones.name] = b
                                        b+=1

                            DictGroup = {}

                            i=0
                            for group in bpy.context.active_object.vertex_groups:
                                DictGroup[i]=group.name
                                i+=1
                                        
                            vertexArr = []
                                        
                            if bpy.context.mode == 'OBJECT':
                                for vertex in bpy.data.meshes[mesh_name].vertices:      
                                    for group in range(len(vertex.groups)):
                                            vertexArr.append(vertex.index)
                                            
                            # my_dict = {i:vertexArr.count(i) for i in vertexArr}
                            # for each in range(len(my_dict)):
                            #     if my_dict[each] > 4:
                            #         error = True
                            #         break

                        if error:
                            self.report({"ERROR"}, "1 or more bones have too many weights! Use the Limit Bones button to fix this!")
                        else:
                            for obj in bpy.data.collections['CLOTHING_EXPORT'].all_objects:
                                obj.select_set(True)

                            bpy.data.objects['Clothing_Avatar_Armature'].select_set(True)

                            bpy.ops.export_scene.fbx(
                                filepath= bpy.path.abspath("//" + "Clothing_" + str(exportName.split('.')[0]) + ".fbx"),
                                use_selection= True,
                                add_leaf_bones= False,
                                bake_anim= True,
                                bake_anim_use_all_bones= True,
                                bake_anim_use_nla_strips= False,
                                bake_anim_use_all_actions= False,
                                bake_anim_force_startend_keying= False,
                                bake_anim_step= 1,
                                bake_anim_simplify_factor= 0
                                )

                            self.report({"INFO"}, "Clothing Exported as " + "Clothing_" + str(exportName.split('.')[0]) + "!")

                if "Animation_Scene" in col.name: #Animation Export
                    exported = True
                    if len(bpy.context.view_layer.layer_collection.children) < 1:
                        self.report({"WARNING"}, "No Animation Found!")
                        
                    if "." in col.name:
                        animNum = "." + str(col.name).split(".")[-1]
                    else:
                        animNum = ""

                    children = [] 
                    for ob in bpy.data.objects: 
                        if ob.parent == bpy.data.objects['Anim']: 
                            children.append(ob) 

                    bpy.ops.object.mode_set(mode= 'OBJECT')
                    bpy.ops.object.select_all(action='DESELECT')
                    animObj = ""
                    for subCol in col.children:
                        if("ANIMATION_EXPORT" in subCol.name):
                            bpy.context.view_layer.active_layer_collection = subCol
                            for obj in bpy.data.collections[subCol.name].all_objects:
                                if "Anim" in obj.name:
                                    obj.select_set(True)
                                    animObj = obj
                                    if imvutool.exportClothing:
                                        for clothing in children:
                                            clothing.select_set(True)
                                if "Morph" in obj.name and imvutool.enableMorph:
                                    obj.select_set(True)
                    oldSceneName = bpy.context.scene.name
                    bpy.context.scene.name = "Anim-" + str(animObj.animation_data.action.name)[1:]

                    bpy.data.shape_keys["Key"].key_blocks[1].name = str(animObj.animation_data.action.name)[1:]

                    # if imvutool.enableMorph:
                    #     includeMesh = "MESH"
                    # else:
                    #     includeMesh = "OTHER"

                    if imvutool.isPose:
                        bpy.ops.export_scene.fbx(
                            filepath= bpy.path.abspath("//" + "Pose_" + str(animObj.animation_data.action.name)[1:] + ".fbx"),
                            use_selection= True,
                            add_leaf_bones= False,
                            bake_anim= True,
                            bake_anim_use_all_bones= True,
                            bake_anim_use_nla_strips= False,
                            bake_anim_use_all_actions= False,
                            bake_anim_force_startend_keying= False,
                            bake_anim_step= 1,
                            bake_anim_simplify_factor= 0,
                            object_types={'ARMATURE', 'MESH'}
                            )
                        self.report({"INFO"}, "Animation Exported as " + "Pose_" + str(animObj.animation_data.action.name)[1:] + "!")
                    elif imvutool.exportAll:
                        bpy.ops.export_scene.fbx(
                            filepath= bpy.path.abspath("//" + "Animation_" + str(animObj.animation_data.action.name)[1:] + ".fbx"),
                            use_selection= True,
                            add_leaf_bones= False,
                            bake_anim= True,
                            bake_anim_use_all_bones= True,
                            bake_anim_use_nla_strips= False,
                            bake_anim_use_all_actions= False,
                            bake_anim_force_startend_keying= False,
                            bake_anim_step= 1,
                            bake_anim_simplify_factor= 0,
                            path_mode= "ABSOLUTE",
                            object_types={'ARMATURE', 'MESH'}
                            )
                        self.report({"INFO"}, "Animation Exported as " + "Animation_" + str(animObj.animation_data.action.name)[1:] + "!")
                    else:
                        bpy.ops.export_scene.fbx(
                            filepath= bpy.path.abspath("//" + "Animation_" + str(animObj.animation_data.action.name)[1:] + ".fbx"),
                            use_selection= True,
                            add_leaf_bones= False,
                            bake_anim= True,
                            bake_anim_use_all_bones= False,
                            bake_anim_use_nla_strips= False,
                            bake_anim_use_all_actions= False,
                            bake_anim_force_startend_keying= False,
                            bake_anim_step= 1,
                            bake_anim_simplify_factor= 1,
                            object_types={'ARMATURE', 'MESH'}
                            )
                        self.report({"INFO"}, "Animation Exported as " + "Animation_" + str(animObj.animation_data.action.name)[1:] + "!")

                    
                    bpy.ops.object.select_all(action='DESELECT')
                    bpy.context.scene.name = oldSceneName
                    
                if col.name == "Head_Scene": #Head Export
                    exported = True
                    bpy.ops.object.mode_set(mode='OBJECT')
                    bpy.ops.object.select_all(action='DESELECT')

                    # Bind Heads
                    for each in bpy.data.collections:
                        if "HEAD_EXPORT" in each.name:
                            ogHead = each.objects[0].children[0]
                            for newHead in each.objects:
                                newHead.select_set(True)
                                bpy.context.view_layer.objects.active = ogHead
                    
                    # Delete all keys before adding new ones
                    if not ogHead.data.shape_keys == None:
                        blocks = ogHead.data.shape_keys.key_blocks
                        for ind in reversed(range(len(blocks))):
                            # set active index before remove
                            ogHead.active_shape_key_index = ind
                            bpy.ops.object.shape_key_remove()

                    bpy.ops.object.join_shapes()

                    bpy.ops.object.select_all(action='DESELECT')
                    # Select correct meshes
                    for colChild in bpy.data.collections:
                        if colChild.name == "HEAD_EXPORT":
                            bpy.context.view_layer.objects.active = colChild.objects[0]
                            colChild.objects[0].select_set(True)
                            colChild.objects[0].children[0].select_set(True)
                    
                    # Export
                    bpy.ops.export_scene.fbx(
                        filepath= bpy.path.abspath("//" + "Head_" + str(exportName.split('.')[0]) + ".fbx"),
                        use_selection= True,
                        add_leaf_bones= False,
                        bake_anim= True,
                        bake_anim_use_all_bones= False,
                        bake_anim_use_nla_strips= False,
                        bake_anim_use_all_actions= False,
                        bake_anim_force_startend_keying= False,
                        object_types={'ARMATURE', 'MESH'}
                        )
                    
                    bpy.ops.object.select_all(action='DESELECT')

                    self.report({"INFO"}, "Animation Exported as " + "Head_" + str(exportName.split('.')[0]) + "!")
                            

        if not exported:
            bpy.ops.imvutool.validexport('INVOKE_DEFAULT')



        return {'FINISHED'}

class IMVUTOOL_OT_exportError(bpy.types.Operator):
    bl_label = "Please save your project before exporting"
    bl_idname = "imvutool.export_error"

    def execute(self, context):
        
        return {'FINISHED'}
    
    def invoke(self, context, event):

        return context.window_manager.invoke_props_dialog(self)

class IMVUTOOL_OT_noValidExport(bpy.types.Operator):
    bl_label = "Please create a product before exporting"
    bl_idname = "imvutool.validexport"

    def execute(self, context):
        
        return {'FINISHED'}
    
    def invoke(self, context, event):

        return context.window_manager.invoke_props_dialog(self)

class IMVUTOOL_OT_megaOpen(bpy.types.Operator):
    bl_label = "megaSceneOpen"
    bl_idname = "imvutool.megascene"

    def execute(self, context):
        
        return {'FINISHED'}
    
    def invoke(self, context, event):

        return context.window_manager.invoke_props_dialog(self)

    def draw(self, context):

        layout = self.layout
        row = layout.row()
        row.label(text="Do not modify or try to access the IMVUMegaTool.blend file.")
        row2 = layout.row()
        row2.label(text="Use the tool from an empty blender scene")

class IMVUTOOL_OT_error(bpy.types.Operator):
    bl_label = "Error"
    bl_idname = "imvutool.error"
    bl_description = "Click to print detailed error to [INFO] panel"

    def execute(self, context):
        
        self.report({"INFO"}, errorStr)

        return {'FINISHED'}

def checkValidExport(self, context, exportType):
    if(exportType == "Room"):
        
        self.layer_collection = bpy.data.collections["ROOM_EXPORT"] #Set collection
        
        newList = []
        seatNums = []
        duplicateNums = []

        for each in self.layer_collection.objects:
            newList.append(str(each.name))

        for o in sorted(newList):
            if "seat" in o:
                seatNums.append(o.split(".")[0])

        for elem in seatNums:
            if seatNums.count(elem) > 1:
                duplicateNums.append(elem)
        if (len(duplicateNums) > 0):
            self.report({"WARNING"}, "Duplicate seats found! " + str(duplicateNums))
            return False
        return True

def errorHandling(errorName, row, row2, row4, layout):
    global errorStr
    row.enabled = False
    row2.enabled = False
    row6 = layout.row()
    row6.alignment="CENTER"
    row6.enabled = True
    row6.alert = True
    row6.operator("imvutool.error", text= errorName, icon= "KEYTYPE_EXTREME_VEC")

    if errorName == "Wrong Scene":
        errorStr = "Non-empty scene opened.\nPlease start using the tool from a new blender scene.\nThe default cube, light, and camera can be present."
    elif errorName == "File Not Saved":
        errorStr = "Be sure to save your file before exporting.\nThe exported file will be located in the same folder as your blender scene."


classes = [MyProperties, 
           IMVUTOOL_PT_room_panel, IMVUTOOL_PT_furniture_panel, IMVUTOOL_PT_attachment_panel, IMVUTOOL_PT_clothing_panel, IMVUTOOL_PT_animation_panel, IMVUTOOL_PT_head_panel, IMVUTOOL_PT_export_panel, 
           IMVUTOOL_OT_room_op, IMVUTOOL_OT_room_op1, IMVUTOOL_OT_room_op2, IMVUTOOL_OT_room_op3, IMVUTOOL_OT_room_op4, IMVUTOOL_OT_room_op5, IMVUTOOL_OT_room_op6, IMVUTOOL_OT_room_op7, 
           IMVUTOOL_OT_room_op8, IMVUTOOL_OT_room_op9, IMVUTOOL_OT_room_op10, IMVUTOOL_OT_room_op11, IMVUTOOL_OT_room_op12, 
           IMVUTOOL_OT_room_op13, IMVUTOOL_OT_room_op14, IMVUTOOL_OT_room_op15, IMVUTOOL_OT_room_op16, 
           IMVUTOOL_OT_furniture_op, IMVUTOOL_OT_furniture_op1, IMVUTOOL_OT_furniture_op2, IMVUTOOL_OT_furniture_op3, IMVUTOOL_OT_furniture_op4, 
           IMVUTOOL_OT_furniture_op5, IMVUTOOL_OT_furniture_op6, IMVUTOOL_OT_furniture_op7, IMVUTOOL_OT_furniture_op8, IMVUTOOL_OT_furniture_op9, 
           IMVUTOOL_OT_furniture_op10, IMVUTOOL_OT_furniture_op11, IMVUTOOL_OT_furniture_op12, IMVUTOOL_OT_furniture_op13, IMVUTOOL_OT_furniture_op14,
           IMVUTOOL_OT_furniture_op15, IMVUTOOL_OT_furniture_op16,
           IMVUTOOL_OT_export_op, IMVUTOOL_OT_export_op1, IMVUTOOL_OT_exportError, IMVUTOOL_OT_noValidExport, IMVUTOOL_OT_megaOpen, IMVUTOOL_OT_error,
           IMVUTOOL_OT_clothing_op, IMVUTOOL_OT_clothing_op2, IMVUTOOL_OT_clothing_op3, IMVUTOOL_OT_clothing_op4, IMVUTOOL_OT_clothing_op5, IMVUTOOL_OT_clothing_op6,
           IMVUTOOL_OT_animation_op, IMVUTOOL_OT_animation_op2, IMVUTOOL_OT_animation_op3, IMVUTOOL_OT_animation_op4, IMVUTOOL_OT_animation_op5, 
           IMVUTOOL_OT_animation_op6, IMVUTOOL_OT_animation_op7, IMVUTOOL_OT_animation_op8, IMVUTOOL_OT_animation_op9,
           IMVUTOOL_OT_attachment_op, IMVUTOOL_OT_attachment_op2,
           IMVUTOOL_OT_head_op, IMVUTOOL_OT_head_op2
           ]


def register():
    for cls in classes:
        bpy.utils.register_class(cls)
        bpy.types.Scene.imvu_tool = bpy.props.PointerProperty(type= MyProperties)
        
    bpy.types.Scene.bones = bpy.props.PointerProperty(type=bpy.types.Object)
 
def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
        

if __name__ == "__main__":
    register()