;;; ---------------------------------------------------------------------
;;;  SEQCHK-bgol.lsp
;;;  Command:  SNCK
;;;
;;;  PURPOSE
;;;  Scans a selection of numeric TEXT entities (e.g. parcel numbers,
;;;  point numbers), determines the min/max numeric range, and reports
;;;  every missing number and every duplicated number within that range
;;;  directly at the command line -- a quick QA/QC pass on any serial
;;;  numbering scheme in a drawing.
;;;
;;;  USAGE
;;;    1. Load this file (APPLOAD or drag-drop onto the drawing window).
;;;    2. Type   SNCK   at the command line and press Enter.
;;;    3. Select the numeric TEXT entities to check, press Enter to
;;;       finish.
;;;    4. The command line reports the count and list of missing numbers
;;;       within the min-max range, and the count and list of duplicated
;;;       numbers. Each duplicated text entity is also marked with a
;;;       point on layer "BGOL-SNCK" for a quick visual locate.
;;;
;;;  NOTES
;;;    - This is an original, independently written implementation.
;;;      It is INSPIRED by the general idea of missing/duplicate
;;;      sequence-number checking utilities common in survey/CAD
;;;      drafting workflows, but the code, command name and file name
;;;      here are new and are NOT copied from, nor identical to, any
;;;      specific third-party product.
;;;
;;;  ---------------------------------------------------------------------
;;;  Developed and shared for the CAD community by:  BGol Community
;;;  Community website:                              https://bgol.in/
;;;  License:  Open-source & free to use, modify, and share for all.
;;;            Provided "as is", without warranty of any kind.
;;;  ---------------------------------------------------------------------

(vl-load-com)

(defun BGOL:SNCK-EnsureLayer (lname / )
  (if (not (tblsearch "LAYER" lname))
    (entmake (list '(0 . "LAYER")
                   '(100 . "AcDbSymbolTableRecord")
                   '(100 . "AcDbLayerTableRecord")
                   (cons 2 lname)
                   '(70 . 0)
                   '(62 . 1)          ; red
                   '(6 . "Continuous")))
  )
)

(defun BGOL:SNCK-MarkPoint (obj lname / pt)
  (setq pt (vlax-get obj 'InsertionPoint))
  (entmake (list '(0 . "POINT")
                 (cons 8 lname)
                 (cons 10 pt)))
)

(defun BGOL:SNCK-ListToString (lst / s x)
  (setq s "")
  (foreach x lst
    (setq s (strcat s (if (= s "") "" ",") (itoa x)))
  )
  s
)

(defun C:SNCK ( / ss n i ent edata val vals minv maxv expected k
                  missing dupes seen dup x obj)
  (BGOL:SNCK-EnsureLayer "BGOL-SNCK")
  (princ "\nSelect numeric TEXT entities to check: ")
  (setq ss (ssget '((0 . "TEXT"))))
  (if ss
    (progn
      (setq vals '())
      (setq n (sslength ss))
      (setq i 0)
      (repeat n
        (setq ent (ssname ss i))
        (setq edata (entget ent))
        (setq val (atoi (cdr (assoc 1 edata))))
        (setq vals (cons val vals))
        (setq i (1+ i))
      )
      (setq minv (apply 'min vals))
      (setq maxv (apply 'max vals))
      ;; build expected full sequence
      (setq expected '())
      (setq k minv)
      (while (<= k maxv)
        (setq expected (cons k expected))
        (setq k (1+ k))
      )
      ;; missing = expected values not present in vals
      (setq missing '())
      (foreach x expected
        (if (not (member x vals))
          (setq missing (cons x missing))
        )
      )
      (setq missing (vl-sort missing '<))
      ;; duplicates = values appearing more than once
      (setq dupes '())
      (setq seen '())
      (foreach x vals
        (if (member x seen)
          (if (not (member x dupes)) (setq dupes (cons x dupes)))
          (setq seen (cons x seen))
        )
      )
      (setq dupes (vl-sort dupes '<))
      ;; mark duplicate text entities
      (setq i 0)
      (repeat n
        (setq ent (ssname ss i))
        (setq edata (entget ent))
        (setq val (atoi (cdr (assoc 1 edata))))
        (if (member val dupes)
          (progn
            (setq obj (vlax-ename->vla-object ent))
            (BGOL:SNCK-MarkPoint obj "BGOL-SNCK")
          )
        )
        (setq i (1+ i))
      )
      (princ (strcat "\nRange checked: " (itoa minv) " to " (itoa maxv)))
      (princ (strcat "\nThere are " (itoa (length missing)) " items in Missing List: "
                     (BGOL:SNCK-ListToString missing)))
      (princ (strcat "\nThere are " (itoa (length dupes)) " items in Repeat List: "
                     (BGOL:SNCK-ListToString dupes)))
      (princ "\nDuplicate text entities marked on layer BGOL-SNCK. Press F2 for full text window.")
    )
    (princ "\nNo text selected.")
  )
  (princ)
)

(princ "\nSEQCHK-bgol.lsp loaded. Type SNCK to check missing/duplicate numbers in a sequence.")
(princ "\n  -- Free & open-source, courtesy of BGol Community (https://bgol.in/) --")
(princ)
