;;; ------------------------------------------------------------
;;; AutoCATS ¸®½À ÀÚ·á½Ç
;; ¸í·É: TCALC
;; ±â´É: ¼ýÀÚ·Î¸¸ ±¸¼ºµÈ TEXT/MTEXT/ATTRIB¿¡ »çÄ¢¿¬»ê ÀÏ°ý Àû¿ë
;; ÃâÃ³: https://www.autocats.co.kr/lisp/text-calculate
;; ¹öÀü: 1.0 (2026-07-23)
;; ¶óÀÌ¼±½º: ÀÚÀ¯ »ç¿ë¡¤¼öÁ¤, Àç¹èÆ÷ ½Ã ÃâÃ³(autocats.co.kr) Ç¥±â
;; ¾ÈÀü: *error* ÇÚµé·¯ + UNDO ±×·ì, 0 ³ª´©±â Â÷´Ü, Àá±ä ·¹ÀÌ¾î °Ç³Ê¶Ü
;;; ------------------------------------------------------------

(vl-load-com)

(defun autocats-tcalc-clean (value / result idx char)
  (setq result "" idx 1)
  (while (<= idx (strlen value))
    (setq char (substr value idx 1))
    (if (not (member char '("," " ")))
      (setq result (strcat result char)))
    (setq idx (1+ idx)))
  result)

(defun autocats-tcalc-number (value / clean idx char valid dots signs)
  (setq clean (autocats-tcalc-clean value)
        idx 1 valid (/= clean "") dots 0 signs 0)
  (while (and valid (<= idx (strlen clean)))
    (setq char (substr clean idx 1))
    (cond
      ((wcmatch char "#"))
      ((= char ".") (setq dots (1+ dots)) (if (> dots 1) (setq valid nil)))
      ((member char '("+" "-"))
       (setq signs (1+ signs))
       (if (or (> signs 1) (/= idx 1)) (setq valid nil)))
      (T (setq valid nil)))
    (setq idx (1+ idx)))
  (if (and valid (not (member clean '("+" "-" "." "+." "-."))))
    (distof clean 2)
    nil))

(defun autocats-tcalc-calculate (value operation operand)
  (cond
    ((= operation "Add") (+ value operand))
    ((= operation "Subtract") (- value operand))
    ((= operation "Multiply") (* value operand))
    ((and (= operation "Divide") (/= operand 0.0)) (/ value operand))
    (T nil)))

(defun autocats-tcalc-locked-p (ent / data row)
  (setq data (entget ent)
        row (tblsearch "LAYER" (cdr (assoc 8 data))))
  (and row (= 4 (logand 4 (cdr (assoc 70 row))))))

(defun autocats-tcalc-apply (ent operation operand precision / data target old number result updated)
  (setq data (entget ent)
        target (assoc 1 data)
        old (if target (cdr target) "")
        number (autocats-tcalc-number old))
  (if number
    (progn
      (setq result (autocats-tcalc-calculate number operation operand))
      (if result
        (progn
          (setq updated
                (entmod
                  (subst (cons 1 (rtos result 2 precision)) target data)))
          (if updated (progn (entupd ent) T) nil))
        nil))
    nil))

(defun c:TCALC (/ *error* doc undo-open operation operand precision ss idx ent changed skipped apply-result)
  (defun *error* (msg)
    (if undo-open
      (progn (vla-EndUndoMark doc) (setq undo-open nil)))
    (if (and msg (not (wcmatch (strcase msg) "*CANCEL*,*QUIT*,*EXIT*,*Ãë¼Ò*")))
      (princ (strcat "\n[TCALC] Áß´Ü: " msg)))
    (princ))

  (initget "Add Subtract Multiply Divide")
  (setq operation
        (getkword
          "\n[TCALC] ¿¬»ê ¼±ÅÃ [´õÇÏ±â(Add)/»©±â(Subtract)/°öÇÏ±â(Multiply)/³ª´©±â(Divide)] <Add>: "))
  (if (null operation) (setq operation "Add"))
  (setq operand (getreal "\n¿¬»êÇÒ ¼ýÀÚ: "))
  (if (null operand)
    (princ "\n[TCALC] ¿¬»êÇÒ ¼ýÀÚ¸¦ ÀÔ·ÂÇÏÁö ¾Ê¾Æ Á¾·áÇÕ´Ï´Ù.")
    (if (and (= operation "Divide") (= operand 0.0))
      (princ "\n[TCALC] 0À¸·Î ³ª´­ ¼ö ¾ø½À´Ï´Ù.")
    (progn
      (setq precision (getint (strcat "\n¼Ò¼ö ÀÚ¸´¼ö <" (itoa (getvar "DIMDEC")) ">: ")))
      (if (or (null precision) (< precision 0) (> precision 8))
        (setq precision (getvar "DIMDEC")))
      (princ "\n[TCALC] ¼ýÀÚ ¹®ÀÚ¸¦ ¼±ÅÃÇÏ¼¼¿ä.")
      (setq ss (ssget '((0 . "TEXT,MTEXT,ATTRIB"))))
      (if ss
        (progn
          (setq doc (vla-get-ActiveDocument (vlax-get-acad-object))
                changed 0 skipped 0 idx 0)
          (vla-StartUndoMark doc)
          (setq undo-open T)
          (while (< idx (sslength ss))
            (setq ent (ssname ss idx))
            (if (autocats-tcalc-locked-p ent)
              (setq skipped (1+ skipped))
              (progn
                (setq apply-result
                      (vl-catch-all-apply
                        'autocats-tcalc-apply
                        (list ent operation operand precision)))
                (if (or (vl-catch-all-error-p apply-result) (null apply-result))
                  (setq skipped (1+ skipped))
                  (setq changed (1+ changed)))))
            (setq idx (1+ idx)))
          (vla-EndUndoMark doc)
          (setq undo-open nil)
          (princ (strcat "\n[TCALC] ¿Ï·á: " (itoa changed)
                         "°³ ¼öÁ¤ / " (itoa skipped) "°³ °Ç³Ê¶Ü")))
        (princ "\n[TCALC] ¼±ÅÃµÈ ¹®ÀÚ°¡ ¾ø½À´Ï´Ù.")))))
  (princ))

(princ "\n[AutoCATS] TCALC ·Îµå ¿Ï·á - ¸í·ÉÇà¿¡ TCALC ¸¦ ÀÔ·ÂÇÏ¼¼¿ä.")
(princ)
