;; pbook.el
;;

;;; License
;;
;; This program 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
;; of the License, or (at your option) any later version.
;;
;; This program 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 this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

;; ---------------------------------------------------------------------------
;; pbook small bookmark tool
;; ---------------------------------------------------------------------------

;; add your .emacs
;;
;; (require 'pbook)
;; (define-key global-map "\C-c\C-b" 'pbook::book)
;; (define-key global-map "\C-c\C-r" 'pbook::read)

;;; Developer
;;
;; kobapan
;; kobapan@users.sourceforge.net

(defconst pbookconf "~/.pbook")

;; interactive 
(defun pbook::book (path)
  "make bookmark with current `PATH`"
  (interactive
   (list (pbook::input-path)))
  (pbook::save-path path))

(defun pbook::input-path ()
  "read current path"
  (let (path)
    (if (and (boundp 'running-xemacs) running-xemacs)
        (setq path (read-directory-name "book this path: " default-directory default-directory nil))
      (setq path (read-file-name "book this path: " default-directory default-directory nil)))))

(defun pbook::save-path (path)
  "save `PATH` in .pbook (bookmarks file)"
  (save-excursion
    (set-buffer (find-file-noselect pbookconf))
    (let ((information (concat path "\n")))
      (if (re-search-forward (concat path "\n") nil 0 nil) ; goto-char point-max if not hit
          (replace-match information) ; replace if hit
        (insert information))) ; insert in point-max if not hit
    (basic-save-buffer)
    (kill-buffer nil)))

;; interactive 
(defun pbook::read (path)
  "complement user's input `PATH` in mini buffer using .pbook (bookmarks file)"
  (interactive
   (list (pbook::read-file (pbook::select-path))))
  (find-file path))

(defun pbook::select-path (&optional apropos)
  "show bookmarked path in mini buffer, which is matched with user's input\n 
with no match, recursive call\n
with single match, call `C-c C-f` with matched path\n 
with maltiple match, open selection buffer"
  (let ((input (read-from-minibuffer "apropos?: " apropos))
        lst)
    (setq lst (pbook::study-book input))
    (cond 
     ((null lst) (pbook::select-path))
     ((null (cdr lst)) (car lst))
     (t
      (pbook::select-complete-with-buffer lst)
      (pbook::select-path input)))))

(defun pbook::study-book (needle)
  "regex search `NEEDLE` from .pbook and make complementary list"
  (save-excursion
    (set-buffer (find-file-noselect pbookconf))
    (widen)
    (goto-char (point-min))
    (let* ((lst) (path) (completion-ignore-case t))
      (while (re-search-forward (concat "\\(.*" needle ".*\\)\n") nil t)
        (setq lst (cons (buffer-substring (match-beginning 1) (match-end 1)) lst)))
      (kill-buffer nil)
      lst)))

(defun pbook::read-file (path)
  "call `C-c C-f` with `PATH`"
  (let (ans)
    (if (and (boundp 'running-xemacs) running-xemacs)
        (setq ans (read-directory-name "open this?: " path path nil))
      (setq ans (read-file-name "open this?: " path path nil)))))

;; buffer for select complete
(defun pbook::completion-buffer-mode ()
  "major mode for pbook completion buffer"
  (let ((map (make-sparse-keymap)))
    (setq major-mode 'pbook::completion-buffer-mode)
    (setq mode-name "pbook::completion-buffer-mode")
    (define-key map [double-mouse-1] 'pbook::select-into-minibuffer)
    (define-key map " " 'pbook::select-into-minibuffer)
    (define-key map "\r" 'pbook::select-into-minibuffer)    
    (define-key map "\n" 'pbook::select-into-minibuffer)    
    (setq pbook::completion-buffer-mode map)
    (use-local-map pbook::completion-buffer-mode)))

(defvar pbook::completion-buffer "*<pbook-list>*")

(defun pbook::select-complete-with-buffer (lst)
  "complete mini buffer from completion buffer"
  (save-excursion
    (let ((pbook::buffer (get-buffer-create pbook::completion-buffer)))
      (set-buffer pbook::buffer)
      (pbook::completion-buffer-mode)
      (setq buffer-read-only nil) ; unlock
      (erase-buffer)
      (mapcar (lambda (x) (when (file-directory-p x) (insert x "\n")))
              lst)
      (goto-char (point-min))
      (setq buffer-read-only t)   ; lock
      (pop-to-buffer pbook::buffer))))

;; interactive
(defun pbook::select-into-minibuffer ()
  "select path and insert into minibuffer"
  (interactive)
  (let (path)
    (beginning-of-line)
    (setq path (buffer-substring (point) (progn (end-of-line) (point))))
    (pbook::read-file path)))

(provide 'pbook)
;; pbook.el


