;;; AutoCATS 리습 자료실
;; 명령: TREPLACE
;; 기능: 선택한 일반 TEXT·서식 없는 MTEXT에서 문자열을 찾아 모두 치환합니다.
;; 출처: https://www.autocats.co.kr/lisp/text-replace
;; 버전: 1.0 (2026-10-23)
;; 라이선스: 자유 사용·수정, 재배포 시 출처(autocats.co.kr) 표기
;; 안전: 잠긴 레이어·외부참조 보호, 변경은 UNDO 그룹, 명령별 범위는 상세 가이드 참고

(vl-load-com)

(defun autocats-treplace-safe-p (ent / data row block)
  (setq data (entget ent)
    row (tblsearch "LAYER" (cdr (assoc 8 data))))
  (and data row (= 0 (logand 4 (cdr (assoc 70 row))))
    (or (/= "INSERT" (cdr (assoc 0 data)))
      (and (setq block (tblsearch "BLOCK" (cdr (assoc 2 data))))
        (= 0 (logand 12 (cdr (assoc 70 block))))))))

(defun autocats-treplace-replace-pair (code value data)
  (if (assoc code data) (subst (cons code value) (assoc code data) data)
    (append data (list (cons code value)))))

(defun autocats-treplace-put (ent property value / data)
  (if (autocats-treplace-safe-p ent)
    (progn
      (setq data (entget ent))
      (if (= "MTEXT" (cdr (assoc 0 data)))
        (progn
          (setq data (vl-remove-if '(lambda (pair) (member (car pair) '(1 3))) data))
          (while (> (strlen value) 250)
            (setq data (append data (list (cons 3 (substr value 1 250)))) value (substr value 251)))
          (setq data (append data (list (cons 1 value)))))
        (setq data (autocats-treplace-replace-pair 1 value data)))
      (if (entmod data) (progn (entupd ent) T)))))

(defun autocats-treplace-get (ent property / data value)
  (setq data (entget ent) value "")
  (if (= "MTEXT" (cdr (assoc 0 data)))
    (progn (foreach pair data (if (member (car pair) '(1 3)) (setq value (strcat value (cdr pair))))) value)
    (cdr (assoc 1 data))))

(defun autocats-treplace-batch (selection action / index changed skipped ent result)
  (setq index 0 changed 0 skipped 0)
  (if selection
    (repeat (sslength selection)
      (setq ent (ssname selection index)
        result (if (autocats-treplace-safe-p ent) (vl-catch-all-apply action (list ent))))
      (if (and result (not (vl-catch-all-error-p result)))
        (setq changed (1+ changed))
        (setq skipped (1+ skipped)))
      (setq index (1+ index))))
  (princ (strcat "\n[TREPLACE] 완료: " (itoa changed) " / 건너뜀: " (itoa skipped)))
  (list changed skipped))

(defun autocats-treplace-replace (value old new / start found result)
  (setq start 0 result "")
  (if (/= old "")
    (progn
      (while (setq found (vl-string-search old value start))
        (setq result (strcat result (substr value (1+ start) (- found start)) new)
          start (+ found (strlen old))))
      (strcat result (substr value (1+ start))))))
(defun autocats-treplace-apply (ent old new / value data)
  (setq data (entget ent) value (autocats-treplace-get ent 'TextString))
  (and (/= old "") (member (cdr (assoc 0 data)) '("TEXT" "MTEXT")) value
    (null (vl-string-search "%<" value))
    (or (= "TEXT" (cdr (assoc 0 data)))
      (not (vl-some '(lambda (s) (vl-string-search s value)) '("\\" "{" "}"))))
    (vl-string-search old value)
    (autocats-treplace-put ent 'TextString (autocats-treplace-replace value old new))))

(defun c:TREPLACE (/ *error* undo-open old new selection)
  (defun *error* (msg)
    (if undo-open (progn (command-s "_.UNDO" "_End") (setq undo-open nil)))
    (if (and msg (not (wcmatch (strcase msg) "*CANCEL*,*QUIT*,*EXIT*,*취소*")))
      (princ (strcat "\n[TREPLACE] 중단: " msg)))
    (princ))

  (setq old (getstring T "\n찾을 문자열 (대소문자 구분): "))
  (if (/= old "")
    (progn
      (setq new (getstring T "\n바꿀 문자열 (Enter=삭제): "))

      (princ "\n대상 객체를 선택하세요: ")
      (setq selection (ssget '((0 . "TEXT,MTEXT"))))
      (if selection
        (progn
          (command "_.UNDO" "_Begin")

          (setq undo-open T)
          (autocats-treplace-batch selection '(lambda (ent) (autocats-treplace-apply ent old new)))
          (command "_.UNDO" "_End")
          (setq undo-open nil)))))
  (princ))

(princ "\n[AutoCATS] TREPLACE 로드 완료")
(princ)
