+;; TODO: Clean up the whole footnote code, it is a mess.
+
+(defun aon-footnote-add (pos text)
+ "Adds a footnote at the current position.
+Note that the footnote text must contain all <p>aragraph tags, and that line
+breaks are not allowed."
+ (interactive
+ (let ((xpos (point))
+ (xtext (read-string "Footnote text: ")))
+ (list xpos xtext)))
+ (if (string= text "")
+ (error "No footnote text!"))
+ (let ((tpos (string-match "<p>" text)))
+ (unless (and tpos (= 0 tpos))
+ (error "Footnotes must contain <p>aragraph start and end tags!")))
+ (save-excursion
+ (let*
+ ((sectid (aon-get-sect-id))
+ (fblockstart (aon-find-footnote-block sectid))
+ (fnum (if fblockstart
+ (aon-get-next-footnote-num fblockstart)
+ 1))
+ (fid (format "%s-%s" sectid fnum))
+ (fentry
+ (format "\n<footnote id=\"%s-foot\" idref=\"%s\">%s</footnote>"
+ fid fid text))
+ (fref
+ (format "<a id=\"%s\" idref=\"%s-foot\" class=\"footnote\" />"
+ fid fid))
+ (fnth (1+ (aon-count-previous-footnotes sectid)))
+ (flistref
+ (format "(<a idref=\"%s\">%s</a>)" sectid (aon-get-sect-title)))
+ (flistinsertpos
+ (aon-find-footnote-list-insert-pos sectid flistref fnth)))
+ ;; First insert errata list entry
+ (goto-char flistinsertpos)
+ (let ((startpos (point))
+ (endpos (save-excursion
+ (insert "\n" text)
+ (point))))
+ (aon-indent-block startpos endpos))
+ (goto-char flistinsertpos)
+ (search-forward "<p>") ; no line-end-position in xemacs
+ (insert flistref " ")
+ ;; Then errata ref
+ (goto-char pos)
+ (insert fref)
+ ;; And last errata entry in section errata block (which may be created)
+ (if fblockstart
+ (progn ; block exists, go to the right position in it
+ (goto-char fblockstart)
+ (dotimes (i (1- fnth))
+ (search-forward "</footnote>"
+ (save-excursion
+ (goto-char fblockstart)
+ (search-forward "</footnotes>")))))
+ (goto-char (aon-create-footnote-block sectid)))
+ (let ((startpos (point))
+ (endpos (save-excursion
+ (insert fentry)
+ (point))))
+ (aon-indent-block startpos endpos)))))
+
+(defun aon-create-footnote-block (sect)
+ "Creates a footnote block and returns insertion point."
+ (save-excursion
+ (goto-char (aon-get-sect-pos sect))
+ (search-forward "</meta>")
+ (save-excursion
+ (let ((spos (point))
+ (endpos (save-excursion
+ (insert "\n\n<footnotes>\n</footnotes>")
+ (point))))
+ (aon-indent-block spos endpos)))
+ (search-forward "<footnotes>")))
+
+(defun aon-find-footnote-block (sect)
+ "Returns the start of the footnote block of the current section, or nil."
+ (save-excursion
+ (goto-char (aon-get-sect-pos sect))
+ (search-forward "</meta>")
+ (let*
+ ((datastart (save-excursion
+ (search-forward "<data>")))
+ (footstart (save-excursion
+ (search-forward "<footnotes>" datastart t))))
+ footstart)))
+
+(defun aon-get-footnote-num (pos)
+ "Return the numerical sequence number of the footnote on the current line.
+If there are no more footnotes defined here, it returns nil."
+ (interactive "p")
+ (let ((fend (save-excursion
+ (search-forward "</footnotes>"))))
+ (save-excursion
+ (and
+ (re-search-forward aon-re-get-footnote-num fend t)
+ (string-to-number (match-string 1))))))
+
+(defun aon-get-next-footnote-num (pos)
+ "Returns the next footnote id number.
+This will always be the previously highest number plus one."
+ (let ((seq '()))
+ (save-excursion
+ (goto-char pos)
+ (while (setq x (aon-get-footnote-num (point)))
+ (setq seq (cons x seq))
+ (search-forward "</footnote>")
+ (forward-line 1)))
+ (if seq
+ (1+ (car (sort seq '>))) ; prior highest + 1
+ 1))) ; the first
+
+(defun aon-count-previous-footnotes (sect)
+ "Based on the current position, counts the number of footnotes before..."
+ (save-excursion
+ (let ((sectstart (aon-get-sect-pos sect))
+ (count 0))
+ (while (re-search-backward
+ "<a.+?idref=\".+?-foot\".+?class=\"footnote\".*?/>" sectstart t)
+ (setq count (1+ count)))
+ count)))
+
+(defun aon-find-footnote-list-insert-pos (sect ref nth)
+ ""
+ (save-excursion
+ (let ((flistsectpos (aon-get-sect-pos "footnotz")))
+ (if (= nth 1)
+ (aon-find-new-footnote-list-entry-pos (aon-get-sect-pos sect))
+ (progn
+ (goto-char flistsectpos)
+ (dotimes (i (1- nth))
+ (search-forward ref))
+ (end-of-line)
+ (point))))))
+
+;; TODO: This code is mostly copied from the errata code. Merge them?
+
+(defun aon-find-new-footnote-list-entry-pos (sectpos)
+ "Return the position where a new footnote list entry shall be created."
+ (save-excursion
+ (goto-char (aon-get-sect-pos "footnotz"))
+ (search-forward "<data>")
+ (forward-line 1) ; pos is now on the line of the first <p> (if it exists)
+ (let ((endofflist
+ (save-excursion
+ (if (search-forward "</data>")
+ (point)
+ (error "Could not find the end of the footnotes list!")))))
+ (while (let ((id (save-excursion
+ (if (re-search-forward aon-re-get-errata-entry-id
+ endofflist
+ t)
+ (match-string 1)
+ "illstrat" ; hack warning! to avoid getting too far
+ ))))
+ (unless (setq thissectpos (aon-get-sect-pos id))
+ (error
+ "Section %s has a footnote list entry, but does not exist!"
+ id))
+ (< thissectpos sectpos))
+ (forward-line 1)))
+ (forward-line -1)
+ (end-of-line)
+ (point)))
+