# https://blender.stackexchange.com/questions/86612/creating-dynamic-blender-properties
# https://blog.hamaluik.ca/posts/dynamic-blender-properties/

# custom panels https://devtalk.blender.org/t/how-to-add-a-new-tab-in-the-properties-editor/2954/5

import os
import time

from .utils_auth import getUserInformation

from .component_utils import findComponentInScene

from .utils_tools import drawToolsInformation, hasToktxInstalled
from .blender_export import lastExportHasErrors
import bpy
from bpy.props import CollectionProperty
from .utils_auto_update import drawUpdateButton
from .utils_bugreport import allowSendingBugReport, canReportABug
from .utils_license import hasLicense
from .utils_npm import getPackageVersions, updatePackageVersions
from .server.server import hasStartedServer
from .utils_web_project import drawCompressionProgress, getCompressionProgress, getLastServerInstallTime, getLastStartServerTime, isCompressing, serverIsRunning, serverIsStarting, tryGetPackageVersion
from .utils_system_requirements import getMinSupportedNodeVersion, getMaxSupportedNodeVersion, hasSupportedNodeVersionInstalled, tryGetNodeVersion
from .settings_addon import getAddonPreferences
from .operators_web import canGenerateProject, hasAnyglTFOrGlbFiles
from .settings_scene import tryGetMainSceneSettings
from . import utils
from .__meta__ import getVersion
from .utils_icons import getPreviewIcon

class NeedleComponents(bpy.types.PropertyGroup):
    def definitions_path_updated(self, context):
        return

    definitions_path = bpy.props.StringProperty(
        name="definitions_path",
        description="Path to the component descriptions file",
        default="*.json",
        # options={'HIDDEN'},
        maxlen=1024,
        subtype='FILE_PATH',
        update=definitions_path_updated
    )



draw_id = 0



hasSupportedNodeVersion = True
installedNodeVersion = None
lastTimeCheckedNodeVersion = 0

class Viewport_PT_NeedleEngineProjectPanel(bpy.types.Panel):
    bl_idname = "OBJECT_PT_NEEDLE_project_viewport"
    bl_label = "Needle Engine Project"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Needle Engine"
    # bl_context = "object"

    @classmethod
    def poll(self, context):
        global hasSupportedNodeVersion, installedNodeVersion, lastTimeCheckedNodeVersion
        if time.time() - lastTimeCheckedNodeVersion > 5:
            lastTimeCheckedNodeVersion = time.time()
            hasSupportedNodeVersion = hasSupportedNodeVersionInstalled()
            installedNodeVersion = tryGetNodeVersion()
            updatePackageVersions(utils.getWebProjectPath())
        return True

    def draw_header(self, context):
        drawProjectPanelHeader(self, context)
    
    def draw(self, context):
        drawProjectPanel(self, context)
        pass

class ProjectPanel(bpy.types.Panel):
    bl_idname = "OBJECT_PT_NEEDLE_project"
    bl_label = "Needle Engine"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "scene"

    @classmethod
    def poll(self, context):
        global hasSupportedNodeVersion, installedNodeVersion, lastTimeCheckedNodeVersion
        if time.time() - lastTimeCheckedNodeVersion > 5:
            lastTimeCheckedNodeVersion = time.time()
            hasSupportedNodeVersion = hasSupportedNodeVersionInstalled()
            installedNodeVersion = tryGetNodeVersion()
            updatePackageVersions(utils.getWebProjectPath())
        return True

    def draw_header(self, context):
        drawProjectPanelHeader(self, context)

    def draw(self, context):
        drawProjectPanel(self, context)


settingsPopupState = {}
def getClosedState(key:str):
    return settingsPopupState.get(key, False)
def setClosedState(key:str, value:bool):
    settingsPopupState[key] = value

def drawProjectSettings(self, context):
    layout = self.layout
    settings = tryGetMainSceneSettings()
    is_viewport_context = (self.bl_space_type == 'VIEW_3D')

    # Section: Export Settings
    section_idname_settings = "NEEDLE_settings_settings"
    section_label_settings = "Export Settings"
    body_settings = None
    if is_viewport_context:
        body_settings = layout.box()
        body_settings.label(text=section_label_settings)
    else:
        closed_settings = getClosedState(section_idname_settings)
        header_settings, body_settings_panel = layout.panel(section_idname_settings, default_closed=closed_settings)
        setClosedState(section_idname_settings, body_settings_panel is None)
        if header_settings:
            header_settings.label(text=section_label_settings)
            header_settings.operator("needle.open_preferences", text="", icon='PREFERENCES')
        body_settings = body_settings_panel

    if body_settings:
        if settings is not None:
            body_settings.prop(settings, "mainScene", text="Main Scene")
        row_export_save = body_settings.row(align=True)
        row_export_save.prop(settings, "exportOnSave", text="Export On Save")
        row_export_save.prop(settings, "compressOnSave", text="Auto Compress")
        row_compression_options = body_settings.row(align=True)
        row_compression_options.prop(settings, "useGzip")
        row_compression_options.prop(settings, "useRapier")
        
        row_progressive = body_settings.row(align=True)
        row_progressive.prop(settings, "useProgressive", text="Use Progressive Textures")
        progressiveTextureOptions = row_progressive.column(align=True)
        progressiveTextureOptions.enabled = settings.useProgressive
        progressiveTextureOptions.prop(settings, "progressiveTextureSize", text="")
        body_settings.prop(settings, "useProgressiveMeshes", text="Use Progressive Meshes")
    layout.separator()

    # Section: Needle Engine Menu
    section_idname_menu = "NEEDLE_settings_menu"
    section_label_menu = "Needle Engine Menu"
    body_menu = None
    if is_viewport_context:
        body_menu = layout.box()
        body_menu.label(text=section_label_menu)
    else:
        closed_menu = getClosedState(section_idname_menu)
        header_menu, body_menu_panel = layout.panel(section_idname_menu, default_closed=closed_menu)
        setClosedState(section_idname_menu, body_menu_panel is None)
        if header_menu:
            header_menu.label(text=section_label_menu)
        body_menu = body_menu_panel

    if body_menu:
        if not is_viewport_context and body_menu: # alignment only for panel body
            body_menu.alignment = 'LEFT'
        needsLicenseLayout = body_menu.row(align=True)
        needsLicenseLayout.enabled = hasLicense()
        needsLicenseLayout.prop(settings, "showNeedleMenuLogo")
        body_menu.prop(settings, "showQRCodeButton")
        row_menu_buttons = body_menu.row(align=True)
        row_menu_buttons.prop(settings, "showMuteButton")
        row_menu_buttons.prop(settings, "showFullscreenButton")
    layout.separator()

    # Section: Animation
    section_idname_animation = "NEEDLE_settings_animation"
    section_label_animation = "Animation"
    body_animation = None
    if is_viewport_context:
        body_animation = layout.box()
        body_animation.label(text=section_label_animation)
    else:
        closed_animation = getClosedState(section_idname_animation)
        header_animation, body_animation_panel = layout.panel(section_idname_animation, default_closed=closed_animation)
        setClosedState(section_idname_animation, body_animation_panel is None)
        if header_animation:
            header_animation.label(text=section_label_animation)
        body_animation = body_animation_panel

    if body_animation:
        body_animation.prop(settings, "nlatracks")
        body_animation.label(text="When enabled a Timeline will automatically play with the NLA tracks")
        body_animation.label(text="Disable this if you use Animator or Animation components in your scene")
    layout.separator()

    # Section: Rendering
    section_idname_rendering = "NEEDLE_settings_rendering"
    section_label_rendering = "Rendering"
    body_rendering = None
    if is_viewport_context:
        body_rendering = layout.box()
        body_rendering.label(text=section_label_rendering)
    else:
        closed_rendering = getClosedState(section_idname_rendering)
        header_rendering, body_rendering_panel = layout.panel(section_idname_rendering, default_closed=closed_rendering)
        setClosedState(section_idname_rendering, body_rendering_panel is None)
        if header_rendering:
            header_rendering.label(text=section_label_rendering)
        body_rendering = body_rendering_panel

    if body_rendering:
        row_orbit = body_rendering.row(align=True)
        row_orbit.prop(settings, "orbitControls")
        row_orbit_options = row_orbit.row(align=True)
        row_orbit_options.enabled = settings.orbitControls
        row_orbit_options.prop(settings, "autoFit")

        row_contact_shadows = body_rendering.row(align=True)
        row_contact_shadows.prop(settings, "contactShadows")
        row_contact_shadows_options = row_contact_shadows.row(align=True)
        row_contact_shadows_options.enabled = settings.contactShadows
        row_contact_shadows_options.prop(settings, "contactShadowsDarkness")

        row_ground_projection = body_rendering.row(align=True)
        row_ground_projection.prop(settings, "groundProjection")
        row_ground_projection_options = row_ground_projection.row(align=True)
        row_ground_projection_options.enabled = settings.groundProjection
        row_ground_projection_options.prop(settings, "groundProjectionHeight")
    layout.separator()

    # Section: WebXR
    section_idname_xr = "NEEDLE_settings_xr"
    section_label_xr = "WebXR"
    body_xr = None
    if is_viewport_context:
        body_xr = layout.box()
        body_xr.label(text=section_label_xr)
    else:
        closed_xr = getClosedState(section_idname_xr)
        header_xr, body_xr_panel = layout.panel(section_idname_xr, default_closed=closed_xr)
        setClosedState(section_idname_xr, body_xr_panel is None)
        if header_xr:
            header_xr.label(text=section_label_xr)
        body_xr = body_xr_panel

    if body_xr:
        webXRComponentInScene = findComponentInScene("WebXR")
        allowWebXRSettings = webXRComponentInScene is None
        if webXRComponentInScene is not None:
            body_xr.label(text="WebXR component found on \"" + webXRComponentInScene.name + "\"")

        webxrOptionsRow1 = body_xr.row(align=True)
        webxrOptionsRow1.enabled = allowWebXRSettings
        webxrOptionsRow1.prop(settings, "vr")
        webxrOptionsRow1.prop(settings, "ar")
        webxrOptionsRow1.prop(settings, "quicklook")

        webxrOptionsRow2 = body_xr.row(align=True)
        webxrOptionsRow2.enabled = allowWebXRSettings
        webxrOptionsRow2.prop(settings, "arScale")
        webxrOptionsRow2.prop(settings, "depthSensing")
    layout.separator()

    # Section: Networking
    section_idname_networking = "NEEDLE_settings_networking"
    section_label_networking = "Networking"
    body_networking = None
    if is_viewport_context:
        body_networking = layout.box()
        body_networking.label(text=section_label_networking)
    else:
        closed_networking = getClosedState(section_idname_networking)
        header_networking, body_networking_panel = layout.panel(section_idname_networking, default_closed=closed_networking)
        setClosedState(section_idname_networking, body_networking_panel is None)
        if header_networking:
            header_networking.label(text=section_label_networking)
        body_networking = body_networking_panel

    if body_networking:
        networkingRow = body_networking.row(align=True)
        networkingRow.prop(settings, "useNetworking")
        networkingRow.prop(settings, "voip")
    layout.separator()

    # Section: Interaction
    section_idname_interaction = "NEEDLE_settings_interaction"
    section_label_interaction = "Interaction"
    body_interaction = None
    if is_viewport_context:
        body_interaction = layout.box()
        body_interaction.label(text=section_label_interaction)
    else:
        closed_interaction = getClosedState(section_idname_interaction)
        header_interaction, body_interaction_panel = layout.panel(section_idname_interaction, default_closed=closed_interaction)
        setClosedState(section_idname_interaction, body_interaction_panel is None)
        if header_interaction:
            header_interaction.label(text=section_label_interaction)
        body_interaction = body_interaction_panel

    if body_interaction:
        row_interaction = body_interaction.row(align=True)
        row_interaction.prop(settings, "remoteSkybox")
        row_interaction.prop(settings, "dropListener")
    layout.separator()


class ProjectSettingsPanel(bpy.types.Panel):
    bl_parent_id = "OBJECT_PT_NEEDLE_project"
    bl_idname = "OBJECT_PT_NEEDLE_project_settings"
    bl_label = "Project Settings"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    def draw(self, context):
        drawProjectSettings(self, context)

def drawProjectPanelHeader(self, context):
    self.bl_label = ""
    layout = self.layout
    icon = getPreviewIcon("logo_small")
    if not hasLicense():
        layout.label(text="Needle Engine  — Unlicensed - Non Commercial Use Only", icon_value=icon)
    else:
        layout.label(text="Needle Engine", icon_value=icon)
    #   layout.operator("wm.url_open", text="", icon='URL').url = "https://needle.tools/pricing"
    # layout.operator("needle.open_preferences", text="", icon='PREFERENCES')


def drawProjectPanel(self, context):
    global hasSupportedNodeVersion, installedNodeVersion, lastTimeCheckedNodeVersion
    layout = self.layout
    settings = tryGetMainSceneSettings()
    projectPath = utils.getWebProjectPath()
    webProjectExists = utils.webProjectExists()
    canGenerate = canGenerateProject(projectPath)
    isTempProjectPath = utils.getTempWebProjectPath() == projectPath
    prefs = getAddonPreferences()

    # if not hasLicense():
    #     licenseRow = layout.split(factor=1)
    #     leftCol = licenseRow.column(align=True)
    #     leftCol.label(text="No license detected: Non-commercial use only")
        # licenseRow.operator("needle.open_preferences", text="", icon='PREFERENCES')
        # licenseRow.operator("wm.url_open", text="", icon='URL').url = "https://needle.tools/pricing"
    
    global draw_id
    draw_id += 1
    
    if not utils.isBlenderVersionSupported():
        layout.label(text="Unsupported Blender version. Please update to Blender " + utils.getMinSupportedBlenderVersionString() + " or newer", icon='ERROR')
        return
    header = layout.column(align=True)

    if prefs and hasSupportedNodeVersion and prefs.drawTeamSelectionDropdown(header, context) == False:
        prefs.drawLoginLogoutButton(header, None)
        header.separator()
    
    header.prop(settings, "projectPath", text="Web Project Path")
    if not webProjectExists:
        # Handle vanillajs project (e.g. only -> index.html)
        if utils.getIsVanillaJsProject():
            layout.operator("needle_scene.export", text="Export Scene", icon='EXPORT')
            previewLayout = layout.row(align=True)
            previewLayout.enabled = hasAnyglTFOrGlbFiles()
            horizontalLayout = previewLayout.row(align=True)
            horizontalLayout.operator("needle.start_vanilla_server", text="Preview Scene", icon='PLAY')
            stopPreviewLayout = horizontalLayout.row(align=True)
            stopPreviewLayout.enabled = hasStartedServer()
            stopPreviewLayout.operator("needle.stop_vanilla_server", text="Stop Preview", icon='PAUSE')
            layout.operator("scene.needle_open_project", text="Open Directory", icon='FILE_TICK')
            drawProjectFooter(self, layout, projectPath)
            return
        if settings.projectPath and projectPath and not canGenerate:
            header.label(text="Project directory is not empty or invalid (missing package.json)", icon='ERROR')
    # show warnings if the project path is invalid or not empty
    if not webProjectExists:
        if not settings.projectPath:
            header.label(text="Choose a custom directory for the web project (optional)", icon='INFO')
    elif isTempProjectPath:
        header.label(text="Choose a project path to make persistent changes to the web project", icon='INFO')
    
    header.separator()
    el = layout.column(align=True)
    # el.enabled = utils.projectIsSaved()
    
    row = el.row(align=True)
    if not webProjectExists and canGenerate:
        generateProjectRow = row.column(align=False)
        generateProjectRow.enabled = not webProjectExists and canGenerate
        viteProjectLayout = generateProjectRow.column(align=True)
        generateButtonsRow = viteProjectLayout.column(align=False)
        # hasSupportedNodeVersion = False

        # viteProjectLayout.enabled = self.hasSupportedNodeVersion
        if not hasSupportedNodeVersion:
            nodeJsLayout = generateButtonsRow.row(align=True)
            nodeJsLayout.scale_y = 2
            open_nodejs = nodeJsLayout.operator("wm.url_open", text="Install Nodejs", icon='URL', depress=True)
            open_nodejs.url = "https://nodejs.org"
            viteProjectLayout.label(text="Nodejs " + getMinSupportedNodeVersion() + " or " + getMaxSupportedNodeVersion() + " is required to use all features:", icon='ERROR')
        else:
            viteButtonLayout = generateButtonsRow.row(align=True)
            viteButtonLayout.scale_y = 2
            viteProject = viteButtonLayout.operator("needle.generate_project", text=f"Generate Web Project (recommended)", icon='FILE_TICK', depress=True)
            viteProject.templateName = "vite"

        vanillaProject = generateButtonsRow.operator("needle.generate_project", text="Generate HTML Project", icon='FILE_TICK')
        vanillaProject.templateName = "vanilla"
        
        drawProjectFooter(self, el, projectPath)
        return
    elif not hasSupportedNodeVersion:
        el.label(text="Nodejs " + getMinSupportedNodeVersion() + " or " + getMaxSupportedNodeVersion() + " is required:", icon='ERROR')
        nodeJsLayout = el.row(align=True)
        nodeJsLayout.scale_y = 2
        open_nodejs = nodeJsLayout.operator("wm.url_open", text="Open Nodejs Website", icon='URL', depress=True)
        open_nodejs.url = "https://nodejs.org/en/download/"
        drawProjectFooter(self, el, projectPath)
        return

    projectActions = el.column(align=False)
    projectActions.enabled = webProjectExists

    projectRow = projectActions.row(align=False)
    # projectRow.enabled = not isTempProjectPath
    projectRow.operator("scene.needle_open_project", text="Open Directory", icon='FILE_TICK')
    projectRow.operator("scene.open_workspace", text="Open Code Editor", icon='FILE_TICK')

    # projectRow = projectActions.row(align=True)
    timeSinceLastServerStart = time.time() - getLastStartServerTime()
    timeSinceLastServerInstall = time.time() - getLastServerInstallTime()
    installLayout = projectActions.row(align=False)
    if timeSinceLastServerStart < 5 or serverIsStarting() or timeSinceLastServerInstall < 5:
        installLayout.enabled = False
    installLayout.operator("needle.install", text="Install Preview Server", icon='NLA_PUSHDOWN')
    

    if not serverIsRunning():
        installLayout.operator("needle.start_server", text="Start Preview Server", icon='PLAY', depress=True)
    elif timeSinceLastServerStart < 5 or serverIsStarting(): # show some feedback that the server is starting, we dont really know here how long this takes (especially for the first time)
        dots = ""
        for i in range(0, int(draw_id % 4)):
            dots += "."
        installLayout.operator("needle.stop_server", text="Starting Preview Server" + dots, icon='PLAY', depress=webProjectExists)
        if serverIsStarting():
            installLayout.label(text="Starting server - this might take a moment. Your browser should open when it's done", icon='INFO')
    else:
        installLayout.operator("needle.stop_server", text="Stop Preview Server", icon='PAUSE', depress=webProjectExists)

    exportRow = projectActions.column(align=False)
    exportRow.scale_y = 2
    exportRow.operator("needle_scene.export", text="Export To Browser Preview", icon='TRIA_RIGHT')
    drawCompressionProgress(projectActions)
    if lastExportHasErrors():
        projectActions.separator()
        info = projectActions.split(factor=0.5)
        info.label(text="Last export failed...", icon='ERROR')
        info.operator("needle.open_log", text="Open Log", depress=True)

    projectActions.separator()
    projectActions.label(text="Build Actions")
    _hasLicense = hasLicense()
    buildRow = projectActions.row(align=False)
    buildRow.enabled = _hasLicense
    buildDev = buildRow.operator("needle.build_dist", text="Build: Development", icon='STICKY_UVS_LOC')
    buildDev.production = False
    buildProductionRow = buildRow.row(align=True)
    buildProductionRow.enabled = hasToktxInstalled()
    buildProd = buildProductionRow.operator("needle.build_dist", text="Build: Production", icon='STICKY_UVS_LOC')
    buildProd.production = True

    deployToNeedleCloudButtonLayout = projectActions.row()
    deployToNeedleCloudButtonLayout.scale_y = 2
    # user = getUserInformation()
    # if not user or user.authenticated == False:
    #     op = deployToNeedleCloudButtonLayout.operator("needle.open_preferences", text="Login to Deploy to Needle Cloud", icon='PREFERENCES')
    #     op.showMessage = "You need to login to deploy your project to Needle Cloud. Please click login in the addon preferences."
    # else:
    deployToNeedleCloudButtonLayout.operator("needle.deploy_to_needle", text="Deploy to Needle Cloud", emboss=True, icon="EXPORT")

    
    drawToolsInformation(projectActions)
    
    drawProjectFooter(self, projectActions, projectPath)



def drawProjectFooter(self, layout, projectDirectory:str):
    global installedNodeVersion
    
    # licenseRow = layout.row(align=True)
    # licenseOp = licenseRow.operator("wm.url_open", text="Commercial Plans", icon="INFO")
    # licenseOp.url = "https://needle.tools/pricing"

    layout.separator(factor=1)

    # version
    ver = getVersion()
    el = layout.row(align=True)


    footerLayout = el.column(align=True)
    # logo = getPreviewIcon("logo_small")
    # el.operator("wm.url_open", text="", icon_value=logo).url = "https://needle.tools"

    versionStr = "Addon " + str(ver)
    if projectDirectory and os.path.exists(projectDirectory):
        packageVersions = getPackageVersions(projectDirectory,  ["@needle-tools/engine"])
        if packageVersions and packageVersions["@needle-tools/engine"] is not None:
            engineVersion = packageVersions["@needle-tools/engine"]
            if engineVersion.startswith("file:"):
                versionStr += ", Local NE"
            else:
                engineVersion = tryGetPackageVersion(projectDirectory, "@needle-tools/engine", engineVersion)
                versionStr += ", NE " + engineVersion

    if(installedNodeVersion):
        versionStr += ", Node " + str(installedNodeVersion)
    else:
        versionStr += ", Node not installed"

    footerLayout.label(text=versionStr)

    docsOp = el.operator("wm.url_open", text="", icon="HELP", depress=True)
    docsOp.url = "https://docs.needle.tools/blender"

    el.operator("needle.open_changelog", text="", icon="FILE_TEXT")

    latestVersion = utils.getLatestVersion()
    if latestVersion != None and latestVersion != ver:
        # updateIcon = getPreviewIcon("update")
        layout.separator()
        layout.label(text="A new addon version is available:")
        drawUpdateButton(layout, latestVersion)
        # layout.operator("needle.auto_update", text="Update to " + latestVersion, icon='LIGHT', depress=True)
        # layout.operator("wm.url_open", text="Download Update " + latestVersion, icon='LIGHT').url = "https://engine.needle.tools/downloads/blender"

    if not hasLicense():
        el.operator("wm.url_open", text="", icon='URL').url = "https://needle.tools/pricing"
    el.operator("needle.open_preferences", text="", icon='PREFERENCES')
# class GameObjectPanel(bpy.types.Panel):
#     """Creates a Panel in the Object properties window"""
#     bl_idname = "OBJECT_PT_NEEDLE_gameObject"
#     bl_label = "Needle GameObject"
#     bl_space_type = 'PROPERTIES'
#     bl_region_type = 'WINDOW'
#     bl_context = "object"
#     bl_category = "Custom_Editor"

#     def draw(self, context):
#         layout = self.layout
#         el = layout.column(align=True)


class ComponentsPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_idname = "OBJECT_PT_NEEDLE_components"
    bl_label = "Needle Components"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"
    bl_category = "Custom_Editor"

    def draw_header(self, context):
        layout = self.layout
        icon = getPreviewIcon("logo_small_bw")
        layout.label(text="", icon_value=icon)

    def draw(self, context):
        layout = self.layout
        el = layout.column(align=False)
        isTempProject = utils.isTempProject()
        hasActiveObject = len(context.selected_objects) > 0
        el.enabled = hasActiveObject 
        el.operator("wm.component_selection", text="Add Component", icon="ADD", depress=hasActiveObject)
        if not hasActiveObject:
            el.label(text="Select an object to add a component", icon='INFO')

        webProjectExists = utils.webProjectExists()
        if webProjectExists and isTempProject == False:
            nodeLayout = el.column(align=True)
            if not hasSupportedNodeVersionInstalled():
                nodeLayout.enabled = False
                nodeLayout.label(text="Nodejs " + getMinSupportedNodeVersion() + " or " + getMaxSupportedNodeVersion() + " is required for automatic Blender Component generation.", icon='INFO')
            nodeLayout.operator("needle.create_new_component", text="Create New Component", depress=False)





def register():
    # bpy.types.Object.components = CollectionProperty(type=CustomProp)
    # bpy.utils.register_class(ComponentsPanel)
    # bpy.utils.register_class(ProjectPanel)
    pass

def unregister():
    # del bpy.types.Object.components
    # bpy.utils.unregister_class(ComponentsPanel)
    # bpy.utils.unregister_class(ProjectPanel)
    pass