(in-package :html-jen)
(defun dosya-metni-oku (dosya)
  (let* ((uzunluk 0)
         (metin
           (with-output-to-string (out)
             (with-open-file (in dosya :external-format :utf-8)
               (loop :with arabellek := (make-array 8192 :element-type 'character)
                     :for n := (read-sequence arabellek in)
                     :while (< 0 n)
                     :do (incf uzunluk n)
                         (write-sequence arabellek out :start 0 :end n))))))
    (values metin uzunluk)))
(defclass okur ()
  ((metin :initarg :metin :accessor metin
          :documentation "Markdown string")
   (i :initform 0 :accessor i
      :documentation "Metin indeksi")
   (uzunluk :initarg :uzunluk :accessor uzunluk
            :documentation "Metin uzunluğu")
   (dosya-ismi :initarg :dosya-ismi
               :documentation "Okunan markdown dosyasının ismi")))
(defun okur! (dosya-ismi)
  (multiple-value-bind (metin uzunluk)
      (dosya-metni-oku dosya-ismi)
    (make-instance 'okur :metin metin :uzunluk uzunluk :dosya-ismi dosya-ismi)))
(defmethod son? ((okur okur))
  (>= (i okur)
      (uzunluk okur)))
(defmethod index-reset ((okur okur))
  (setf (i oo) 0))
(let ((blok-sonu (format nil "~%~%")))
  (defmethod sonraki-blok ((okur okur))
    (unless (son? okur)
      (with-slots (i uzunluk metin) okur
        (let ((son (or (search blok-sonu metin :start2 i)
                       uzunluk)))
          (prog1 (make-array (- son i)
                             :element-type 'character
                             :displaced-to metin
                             :displaced-index-offset i)
            (setf i (+ son 2))))))))
(defmethod okur-blok-listesi ((okur okur))
  (let ((blok (sonraki-blok okur)))
    (if (null blok)
        nil
        (cons blok (okur-blok-listesi okur)))))
(defgeneric ayrıştır (tag blok baş)
  (:documentation "Tag'a göre bloktaki elementleri belirler."))
(defmethod ayrıştır ((tag (eql :h)) blok baş)
  (let ((i baş)
        (son (length blok))
        (h-sayı 0))
    (loop :while (char= #\# (char blok i))
          :do (incf i)
              (incf h-sayı))
    (assert (char= #\Space (char blok i)))
    (assert (< h-sayı 7))
    (incf i)
    (values (make-array (- son i)
                        :element-type 'character
                        :displaced-to blok
                        :displaced-index-offset i)
            h-sayı)))
(defmethod ayrıştır ((tag (eql :ul)) blok baş)
  (let ((i baş)
        (son (length blok)))
    (loop :while (< i son)
          :do (assert (string= "- " blok :start2 i :end2 (+ i 2)))
              (incf i 2)
          :collect (let ((yeni (or (position #\Newline blok :start i)
                                   son)))
                     (prog1 (make-array (- yeni i)
                                        :element-type 'character
                                        :displaced-to blok
                                        :displaced-index-offset i)
                       (setf i (+ yeni 1)))))))
(defmethod ayrıştır ((tag (eql :ol)) blok baş)
  (let ((i baş)
        (son (length blok))
        (item-sayısı 1))
    (loop :while (< i son)
          :do (let ((i2 i))
                (loop :while (char<= #\0 (char blok i2) #\9)
                      :do (incf i2))
                (assert (string= ". " blok :start2 i2 :end2 (+ i2 2)))
                (assert (= item-sayısı (parse-integer blok :start i :end i2)))
                (incf item-sayısı)
                (setf i (+ i2 2)))
          :collect (let ((yeni (or (position #\Newline blok :start i)
                                   son)))
                     (prog1 (make-array (- yeni i)
                                        :element-type 'character
                                        :displaced-to blok
                                        :displaced-index-offset i)
                       (setf i (+ yeni 1)))))))
(defmethod ayrıştır ((tag (eql :code)) blok baş)
  (let ((son (length blok))
        (kod-baş (+ baş 3))
        (kod-son (- (length blok) 3)))
    (assert (string= "```" blok :start2 baş :end2 kod-baş))
    (assert (string= "```" blok :start2 kod-son :end2 son))
    (make-array (- kod-son kod-baş)
                :element-type 'character
                :displaced-to blok
                :displaced-index-offset kod-baş)))
(defun blok-ayrıştır (blok)
  (let ((i 0))
    (loop :while (char= #\Space (char blok i))
          :do (incf i))
    (case (char blok i)
      (#\# (ayrıştır :h blok i))
      (#\- (ayrıştır :ul blok i))
      (#\` (ayrıştır :code blok i))
      ;; (#\> :blockquote)
      (t (if (char<= #\0 (char blok i) #\9)
             (ayrıştır :ol blok i)
             :p))
      )))