;;; ============================================================
;;;  SPIS_TOOLS.lsp — единый загрузчик инструментов СПИС
;;;
;;;  AutoCAD 2020 и 2026. Кодировка Windows-1251.
;;;
;;;  Папка скриптов определяется АВТОМАТИЧЕСКИ и запоминается:
;;;    1) реестр  HKCU\Software\GENPRO\SPIS\ToolsDir
;;;    2) пути поддержки AutoCAD (findfile)
;;;    3) поиск SPIS_TOOLS.lsp в доверенных путях (до 3 уровней)
;;;  Найденная папка добавляется в TRUSTEDPATHS (снимает диалог
;;;  безопасности) и сохраняется в реестр — второй раз мгновенно.
;;;
;;;  Если автопоиск не сработал — команда SPISSETDIR.
;;;
;;;  Команды:
;;;    SPISSETDIR      — указать папку СПИС вручную
;;;    SPISRUNSETS     — собрать файлы дисциплин (фоном, Python)
;;;    SPISATTACHSETS  — подключить АР и дисциплины в СПИС
;;;    XRLIST  XRBIND  XRBIND1  XRPATH  XRUNBIND  XRDETACH
;;;    SPISHELP        — справка
;;; ============================================================

(vl-load-com)

(setq *SPIS-REG* "HKEY_CURRENT_USER\\Software\\GENPRO\\SPIS")
(setq *SPIS-SUBS* (list "SPIS_RUN_SETS.lsp" "SPIS_SYSTEM_SETS.lsp"
                        "XRBIND.lsp" "SPISHELP.lsp"))
(setq *SPIS-DIR* nil)

;; ---------- мелкие утилиты ----------
(defun spis:trim (s) (vl-string-right-trim "\\/" s))

(defun spis:split (str sep / pos res)
  (setq res nil)
  (while (setq pos (vl-string-search sep str))
    (setq res (cons (substr str 1 pos) res)
          str (substr str (+ pos 1 (strlen sep)))))
  (reverse (cons str res)))

;; Есть ли в папке загрузчик?
(defun spis:here-p (dir / full)
  (if (and dir (> (strlen dir) 0))
    (progn
      (setq full (strcat (spis:trim dir) "\\SPIS_TOOLS.lsp"))
      (if (findfile full) T nil))
    nil))

;; ---------- реестр: запомнить/прочитать папку ----------
(defun spis:reg-get ( / r)
  (setq r (vl-catch-all-apply 'vl-registry-read (list *SPIS-REG* "ToolsDir")))
  (if (vl-catch-all-error-p r) nil r))

(defun spis:reg-set (dir)
  (vl-catch-all-apply 'vl-registry-write (list *SPIS-REG* "ToolsDir" dir)))

;; ---------- добавить папку в TRUSTEDPATHS ----------
(defun spis:ensure-trusted (dir / tp full)
  (setq full (strcase (spis:trim dir)))
  (setq tp (getvar "TRUSTEDPATHS"))
  (if (vl-string-search full (strcase tp))
    (princ)
    (progn
      (setvar "TRUSTEDPATHS" (strcat tp ";" (spis:trim dir)))
      (princ (strcat "\n  Доверенный путь добавлен: " (spis:trim dir))))))

;; ---------- рекурсивный поиск папки с загрузчиком ----------
(defun spis:scan (dir depth / subs s found r)
  (setq found nil)
  (if (spis:here-p dir)
    (setq found dir)
    (if (> depth 0)
      (progn
        (setq r (vl-catch-all-apply 'vl-directory-files (list dir "*" -1)))
        (if (not (vl-catch-all-error-p r))
          (foreach s r
            (if (and (null found)
                     (/= s ".") (/= s "..")
                     (vl-file-directory-p (strcat dir "\\" s)))
              (setq found (spis:scan (strcat dir "\\" s) (1- depth)))))))))
  found)

;; ---------- корни для поиска: пути поддержки + доверенные ----------
(defun spis:candidate-roots ( / acc)
  (setq acc (spis:split (getvar "ACADPREFIX") ";"))
  (setq acc (append acc (spis:split (getvar "TRUSTEDPATHS") ";")))
  acc)

;; ---------- определить папку ----------
(defun spis:detect ( / d f roots)
  (setq d (spis:reg-get))                            ;; 1) реестр
  (if (not (spis:here-p d)) (setq d nil))
  (if (null d)                                       ;; 2) пути поддержки
    (if (setq f (findfile "SPIS_TOOLS.lsp"))
      (setq d (vl-filename-directory f))))
  (if (null d)                                       ;; 3) скан доверенных/поддержки
    (progn
      (setq roots (spis:candidate-roots))
      (foreach r roots
        (if (and (null d) (vl-file-directory-p r))
          (setq d (spis:scan (spis:trim r) 3))))))
  d)

;; ---------- загрузка одного файла по полному пути ----------
(defun spis:load-one (dir fname / full r)
  (setq full (strcat (spis:trim dir) "\\" fname))
  (if (findfile full)
    (progn
      (setq r (vl-catch-all-apply 'load (list full)))
      (if (vl-catch-all-error-p r)
        (princ (strcat "\n  [ОШИБКА] " fname ": " (vl-catch-all-error-message r)))
        (princ (strcat "\n  [OK]  " fname))))
    (princ (strcat "\n  [НЕТ] " fname " — не найден в " dir)))
  (princ))

;; ---------- ручная установка папки ----------
(defun c:SPISSETDIR ( / dir)
  (setq dir (getstring T "\nПапка с файлами СПИС (например Y:/BIM/Autocad PLUGINS/SPIS): "))
  (setq dir (spis:trim (vl-string-translate "/" "\\" dir)))
  (cond
    ((= dir "") (princ "\n  Пусто — ничего не изменено."))
    ((not (spis:here-p dir)) (princ "\n  В этой папке нет SPIS_TOOLS.lsp."))
    (T
      (setq *SPIS-DIR* dir)
      (spis:reg-set dir)
      (spis:ensure-trusted dir)
      (princ (strcat "\n  Папка сохранена: " dir))
      (princ "\n  Перезагрузите SPIS_TOOLS.lsp (APPLOAD) для подключения команд.")))
  (princ))

;; ============================================================
;;  ЗАГРУЗКА
;; ============================================================
(princ "\n==============================================")
(princ "\n  Загрузка инструментов СПИС")
(princ "\n==============================================")

(if (setq *SPIS-DIR* (spis:detect))
  (progn
    (princ (strcat "\n  Папка: " *SPIS-DIR*))
    (spis:reg-set *SPIS-DIR*)
    (spis:ensure-trusted *SPIS-DIR*)
    (foreach f *SPIS-SUBS* (spis:load-one *SPIS-DIR* f))
    (princ "\n\n  Команды:")
    (princ "\n    SPISRUNSETS     — собрать файлы дисциплин")
    (princ "\n    SPISATTACHSETS  — подключить дисциплины в СПИС")
    (princ "\n    XRLIST XRBIND XRBIND1 XRPATH XRUNBIND XRDETACH")
    (princ "\n    SPISHELP        — справка")
    (princ "\n    SPISSETDIR      — указать папку вручную"))
  (progn
    (princ "\n  Папка с инструментами не найдена автоматически.")
    (princ "\n  Выполните команду SPISSETDIR и укажите путь, например:")
    (princ "\n    Y:/BIM/Autocad PLUGINS/SPIS")))
(princ "\n==============================================")
(princ)

;;; Автозагрузка: APPLOAD -> Содержимое -> Добавить -> SPIS_TOOLS.lsp
;;; либо строка в acaddoc.lsp (путь подставьте свой):
;;;   (setvar "TRUSTEDPATHS" (strcat (getvar "TRUSTEDPATHS") ";Y:\\BIM\\Autocad PLUGINS\\SPIS"))
;;;   (load "Y:/BIM/Autocad PLUGINS/SPIS/SPIS_TOOLS.lsp")
