# coding: utf-8
# python 2 only

# Copyright (c) 2026 TormachTips.com. All rights reserved.
# Licensed under the TormachTips Personal Use License.
# Permission is granted only for private personal use and private personal modification.
# No sharing, publication, distribution, resale, sublicensing, screenshots, code excerpts,
# benchmarks, or videos are permitted without prior written permission.
# Requests:         tormach.1100m@gmail.com
# Information page: https://tormachtips.com/plugins.htm

################################################
##                                            ##
##      Auto Load G-Code at Startup 0.96      ##
##          www.tormachtips.com               ##
##                                            ##
################################################

# 0.96 - Public beta. - 6/07/2026

import os
import ConfigParser
import glib
import subprocess
import gtk
import constants
import singletons
from ui_hooks import plugin

CURRENT_VER      = "0.96"
SCRIPT_NAME      = "Auto Load G-Code Plugin"
DESCRIPTION      = "Loads a configured g-code file automatically when PathPilot starts."
ENABLED          = 1
DEV_MACHINE      = 1
DEV_MACHINE_FLAG = "/home/operator/gcode/python/dev_machine.txt"
CONFIG_FILE_PATH = "/home/operator/gcode/python/auto_load_gcode.ini"
STARTUP_DELAY_MS = 3000
RETRY_DELAY_MS   = 500
MAX_TRIES        = 60

class UserPlugin(plugin):
    def __init__(self):
        try:
            import update_checker
            update_checker.tormachtips(__file__, CURRENT_VER)
        except Exception:
            pass
        plugin.__init__(self, "Auto Load G-Code")
        dev_machine_found = os.path.exists(DEV_MACHINE_FLAG)
        if dev_machine_found:
            plugin_enabled = DEV_MACHINE
        else:
            plugin_enabled = ENABLED
        if plugin_enabled:
            self.ui = None
            self.try_count = 0
            self.loaded = False
            self.popup_shown = False
            self.config_created = False
            self.gcode_file_path = self.read_configured_gcode_file_path()
            self.error_handler.write("[Auto Load G-Code] Loaded - checking in 3 seconds", constants.ALARM_LEVEL_QUIET)
            glib.timeout_add(STARTUP_DELAY_MS, self.try_load)
            return
        else:
            if dev_machine_found:
                self.error_handler.write("[Auto Load G-Code] Dev machine found. Plugin loaded, but disabled by DEV_MACHINE.", constants.ALARM_LEVEL_QUIET)
            else:
                self.error_handler.write("[Auto Load G-Code] Plugin loaded, but disabled.", constants.ALARM_LEVEL_QUIET)
                self.error_handler.write("[Auto Load G-Code] To enable, open script, find ENABLED = 0 and change to ENABLED = 1", constants.ALARM_LEVEL_QUIET)
            return

    def read_configured_gcode_file_path(self):
        if os.path.isfile(CONFIG_FILE_PATH):
            return self.read_existing_config()
        self.create_default_config()
        self.config_created = True
        return ""

    def read_existing_config(self):
        config = ConfigParser.ConfigParser()
        try:
            config.read(CONFIG_FILE_PATH)
            if config.has_section('auto_load_gcode') and config.has_option('auto_load_gcode', 'file_path'):
                file_path = config.get('auto_load_gcode', 'file_path').strip()
                if file_path:
                    return os.path.expanduser(file_path)
        except Exception, e:
            self.error_handler.write("[Auto Load G-Code] INI read error: " + str(e), constants.ALARM_LEVEL_LOW)
        return ""

    def create_default_config(self):
        try:
            config_dir = os.path.dirname(CONFIG_FILE_PATH)
            if os.path.isdir(config_dir):
                pass
            else:
                os.makedirs(config_dir)
            f = open(CONFIG_FILE_PATH, 'w')
            f.write("[auto_load_gcode]\n")
            f.write("file_path =\n")
            f.write("\n")
            f.write("# Sample settings:\n")
            f.write("# file_path = /home/operator/gcode/spindle.warmup.nc\n")
            f.write("# file_path = /home/operator/gcode/test.nc\n")
            f.write("\n")
            f.write("# Leave file_path blank to load nothing when PathPilot starts.\n")
            f.close()
            self.error_handler.write("[Auto Load G-Code] Created INI: " + CONFIG_FILE_PATH, constants.ALARM_LEVEL_QUIET)
        except Exception, e:
            self.error_handler.write("[Auto Load G-Code] INI create error: " + str(e), constants.ALARM_LEVEL_LOW)

    def show_first_run_popup(self):
        try:
            parent = None
            if self.ui and hasattr(self.ui, 'window'):
                parent = self.ui.window
            dialog = gtk.MessageDialog(parent, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, "Auto Load G-Code Plugin")
            dialog.set_title("Auto Load G-Code Plugin")
            dialog.format_secondary_text("A new INI file was created:\n\n" + CONFIG_FILE_PATH + "\n\nTo load a file when PathPilot starts, edit the INI and set file_path.\n\nExample:\nfile_path = /home/operator/gcode/spindle.warmup.nc\n\nLeave file_path blank to load nothing at startup.")
            dialog.add_button("Edit INI now", 1)
            dialog.add_button("OK", gtk.RESPONSE_OK)
            dialog.set_keep_above(True)
            dialog.connect("response", self.on_first_run_popup_response)
            dialog.show_all()
        except Exception, e:
            self.error_handler.write("[Auto Load G-Code] Popup error: " + str(e), constants.ALARM_LEVEL_LOW)
        return False

    def on_first_run_popup_response(self, dialog, response):
        try:
            if response == 1:
                subprocess.Popen(["gedit", CONFIG_FILE_PATH])
        except Exception, e:
            self.error_handler.write("[Auto Load G-Code] Gedit open error: " + str(e), constants.ALARM_LEVEL_LOW)
        try:
            dialog.destroy()
        except Exception:
            pass

    def try_load(self):
        try:
            self.try_count += 1
            if self.loaded:
                return False
            if self.try_count > MAX_TRIES:
                self.error_handler.write("[Auto Load G-Code] Startup load timed out.", constants.ALARM_LEVEL_LOW)
                return False
            if hasattr(singletons, 'g_Machine') and singletons.g_Machine:
                self.ui = singletons.g_Machine
            else:
                return self.retry()
            if getattr(self.ui, 'init_finished', False):
                pass
            else:
                return self.retry()
            if self.config_created and self.popup_shown == False:
                self.popup_shown = True
                self.show_first_run_popup()
            if self.gcode_file_path:
                pass
            else:
                self.error_handler.write("[Auto Load G-Code] No startup file configured.", constants.ALARM_LEVEL_QUIET)
                return False
            if hasattr(self.ui, 'load_gcode_file'):
                pass
            else:
                return self.retry()
            if os.path.isfile(self.gcode_file_path):
                pass
            else:
                self.error_handler.write("[Auto Load G-Code] File not found: " + self.gcode_file_path, constants.ALARM_LEVEL_LOW)
                return False
            if self.machine_busy():
                return self.retry()
            self.ui.load_gcode_file(self.gcode_file_path)
            self.loaded = True
            self.error_handler.write("[Auto Load G-Code] Loaded: " + self.gcode_file_path, constants.ALARM_LEVEL_QUIET)
            return False
        except Exception, e:
            self.error_handler.write("[Auto Load G-Code] Error: " + str(e), constants.ALARM_LEVEL_LOW)
            return False

    def retry(self):
        glib.timeout_add(RETRY_DELAY_MS, self.try_load)
        return False

    def machine_busy(self):
        try:
            if hasattr(self.ui, 'program_running') and self.ui.program_running():
                return True
            if hasattr(self.ui, 'mdi_running') and self.ui.mdi_running():
                return True
        except Exception:
            return True
        return False

DESCRIPTION_LONG = """This plugin automatically loads a configured g-code file when PathPilot starts.</font></p>
    <p><font face="Verdana" size="2">Default file:</font></p>
    <p><font face="Verdana" size="2">/home/operator/gcode/test.nc</font></p>"""