;;; eev-pdfpages.el --- tools to create hyperlinks to pages of PDF files

;; Load with: (load "eev-template.el")
;;            (load "eev-pafpages.el")

;; Copyright (C) 2012 Free Software Foundation, Inc.
;;
;; This file is part of GNU eev.
;;
;; GNU eev is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;;
;; GNU eev is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;
;; Author:     Eduardo Ochs <eduardoochs@gmail.com>
;; Maintainer: Eduardo Ochs <eduardoochs@gmail.com>
;; Version:    2012apr15
;; Keywords:   e-scripts, help, hyperlinks, hypertext

;;; Commentary:

;; First version: 2012jan31.
;; This is very new & experimental...
;;
;; This file implements:
;;
;;   1) a variant of ee-goto-position, `ee-goto-position-page', that
;;      behaves differently when its first argument is a number -
;;      instead of jumping to the beginning of the n-th line of the
;;      file it jumps to the beginning of the n-th "page", where
;;      "pages" are sequences of characters separated by formfeeds,
;;      just as lines are sequences of characters separated by
;;      newlines;
;;
;;   2) a drop-in replacement (!) for `find-pdftotext' that interprets
;;      a numerical argument in the beginning of the pos-spec as the
;;      number of a page, instead of the number of a line;
;;
;;   3) the function `current-page', that tells in which "page" we are
;;      in the current buffer;
;;
;;   4) the command `find-page-links', bound to M-h M-p, that
;;      generates links to the current page of a pdf file converted to
;;      text with find-pdftotext; it also works for PDF or DVI files
;;      being viewed in an external viewer, but then we have to enter
;;      the page number by hand.

;; (find-efunction 'count-lines)
;;
(defun count-formfeeds (start end)
  (save-excursion
    (save-restriction
      (narrow-to-region start end)
      (goto-char (point-min))
      (save-match-data
        (let ((done 0))
          (while (re-search-forward "[\f]" nil t 1)
            (setq done (+ 1 done)))
          done)))))

(defun current-page ()
  (+ 1 (count-formfeeds (point-min) (point))))

(defun forward-formfeeds (n)
  (re-search-forward "[\f]" nil nil n))

(defun ee-goto-position-page (&optional pos-spec &rest rest)
  (when pos-spec
    (cond ((numberp pos-spec)
           (goto-char (point-min))
           (forward-formfeeds (1- pos-spec)))
          ((stringp pos-spec)
           (goto-char (save-excursion             ; This used to be just:
                        (goto-char (point-min))   ; (goto-char (point-min))
                        (search-forward pos-spec) ; (search-forward pos-spec)
                        (point))))                ;
          (t (error "This is not a valid pos-spec: %S" pos-spec)))
    (if rest (ee-goto-rest rest))))

(defun find-sh-page (command &rest pos-spec-list)
  (interactive "sShell command: ")
  (find-eoutput-reuse
   command
   `(insert (shell-command-to-string ,command)))
  (apply 'ee-goto-position-page pos-spec-list))

(defun find-pdftotext (fname &rest rest)
  (apply 'find-sh-page (format "pdftotext -layout %s -" fname) rest))

(defun find-pdftotext (fname &rest rest)
  (apply 'find-sh-page (format "pdftotext -layout -enc Latin1 %s -" fname) rest))

(defun find-djvutotext (fname &rest rest)
  (apply 'find-sh-page (format "djvutxt %s" fname) rest))

;; ----------------------------------------
;; 2012apr15

(defun ee-code-page-parameters (code offset)
  (if offset
      (format "
    (setq find-%spage '(ee-page-parameters \"%s\" %d))
    (setq find-%stext '(ee-page-parameters \"%s\" %d))"
              code code offset   code code offset)
    ""))
(defun ee-code-pdftotext (code pdffile &optional offset)
  (format "
    (defun find-%stext (&rest rest) (interactive)
      (apply 'find-pdftotext %S rest))%s
  " code pdffile  (ee-code-page-parameters code offset)))
(defun code-pdftotext  (c f &optional offset)
  (eval (ee-read (ee-code-pdftotext c f offset))))

(defun ee-code-djvutotext (code djvufile &optional offset)
  (format "
    (defun find-%stext (&rest rest) (interactive)
      (apply 'find-djvutotext %S rest))%s
  " code djvufile  (ee-code-page-parameters code offset)))
(defun code-djvutotext  (c f &optional offset)
  (eval (ee-read (ee-code-djvutotext c f offset))))

;; ----------------------------------------

;; (find-angg ".emacs.papers" "coetzee")
(setq ee-page-stem   "livesofanimals")
(setq ee-page-offset -110)

(defun ee-page-parameters (stem offset)
  (setq ee-page-stem   stem)
  (setq ee-page-offset offset))

(defun ee-find-xxxpage (&optional stem)
  (intern (format "find-%spage" (or stem ee-page-stem))))
(defun ee-find-xxxtext (&optional stem)
  (intern (format "find-%stext" (or stem ee-page-stem))))
(defun ee-last-kill () (ee-no-properties (car kill-ring)))

(defun find-page-links (&optional stem offset page &rest rest)
  "Visit a temporary buffer containing hyperlinks for page."
  (interactive)
  (setq stem   (or stem   ee-page-stem))
  (setq offset (or offset ee-page-offset))
  (setq page   (or page (current-page)))
  (let* ((find-xxxpage (intern (format "find-%spage" stem)))
         (find-xxxtext (intern (format "find-%stext" stem)))
         (kill0        (car kill-ring))
         (kill         (if (stringp kill0) (ee-no-properties kill0)))
         )
    (apply 'find-elinks `(
      (find-page-links ,stem ,offset ,page ,@rest)
      (setq ee-page-stem ,stem)
      (setq ee-page-offset ,offset)
      (ee-page-parameters ,stem ,offset)
      (find-efunction 'find-page-links)
      ""
      (,find-xxxpage ,page)
      (,find-xxxtext ,page)
      (,find-xxxpage (+ ,offset ,(- page offset)))
      (,find-xxxtext (+ ,offset ,(- page offset)))
      ""
      (,find-xxxpage ,page ,kill)
      (,find-xxxtext ,page ,kill)
      (,find-xxxpage (+ ,offset ,(- page offset)) ,kill)
      (,find-xxxtext (+ ,offset ,(- page offset)) ,kill)
      ""
      (find-books "__cats/__cats.el" "awodey")
      (ee-page-parameters "awodeyct" 10)
      ""
      (find-angg ".emacs" "unilog-current")
      (ee-page-parameters "unilogcurr" 0)
      (setq ee-page-stem "854")
      ""
      (find-angg ".emacs.papers" "tesemestr")
      (ee-page-parameters "tesemestr" 7)
    ) rest)))

(define-key eev-mode-map "\M-h\M-p" 'find-page-links)

(defun ee-wrap-page ()
  "Try this example:\n
\(toggle-read-only 0)
\(buffer-enable-undo)
\(ee-page-parameters \"livesofanimals\" -110)
\(eek \"2*<down> <<ee-wrap-page>>\")\n
134 woke up haggard in the mornings\n" 
  (interactive)
  (ee-wrapc '(n str) '(insert (ee-links-to-string
    `((,(ee-find-xxxpage) (+ ,ee-page-offset ,(string-to-int n)) ,str)
      (,(ee-find-xxxtext) (+ ,ee-page-offset ,(string-to-int n)) ,str))))))

;; (find-efunctiondescr 'ee-wrap-page)

(defun ee-wrap-page ()
  "Try this example:\n
\(toggle-read-only 0)
\(buffer-enable-undo)
\(ee-page-parameters \"livesofanimals\" -110)
\(eek \"2*<down> 2*<<ee-wrap-page>>\")\n
134 woke up haggard in the mornings
134 woke up haggard in the mornings\n" 
  (interactive)
  (ee-wrapc '(n str) '(insert (ee-links-to-string
    `((,(ee-find-xxxpage) (+ ,ee-page-offset ,(string-to-int n)) ,str)
      (,(ee-find-xxxtext) (+ ,ee-page-offset ,(string-to-int n)) ,str))
    ))))

(define-key eev-mode-map "\M-P" 'ee-wrap-page)

(provide 'eev-pdfpages)



;; Local Variables:
;; coding:            raw-text-unix
;; ee-anchor-format:  "defun %s "
;; no-byte-compile:   t
;; End: