;;; mew-minibuf.el --- Minibuffer input methods for Mew

;; Author:  Kazu Yamamoto <Kazu@Mew.org>
;; Created: Mar 23, 1997
;; Revised: Oct 25, 1997

;;; Code:

(defconst mew-minibuf-version "mew-minibuf.el version 0.08")

(require 'mew)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Keymap and completion switch
;;;

(defvar mew-input-map nil)

(if mew-input-map
    ()
  (setq mew-input-map (make-sparse-keymap))
  (define-key mew-input-map " "    'mew-input-complete)
  (define-key mew-input-map "\t"   'mew-input-complete)
;;  (define-key mew-input-map "\177" 'backward-delete-char)
;;  (define-key mew-input-map "\C-h" 'mew-complete-backscroll)
  (define-key mew-input-map "\r"   'exit-minibuffer)
  (define-key mew-input-map "\n"   'exit-minibuffer)
  (define-key mew-input-map "\C-g" 'abort-recursive-edit)
  (define-key mew-input-map "\M-p" 'previous-history-element)
  (define-key mew-input-map "\M-n" 'next-history-element)
  )

(defvar mew-input-complete-function nil)

(defun mew-input-complete ()
  (interactive)
  (if (and mew-input-complete-function (fboundp mew-input-complete-function))
      (funcall mew-input-complete-function)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Mew original completion
;;;

(defun mew-input-clear ()
  "A function to clean up side effects of window configuration
at completions."
  (save-excursion
    (set-buffer (window-buffer (minibuffer-window)))
    ;; mew-complete-window-config is shared by many functions
    ;; because minibuffer is just one!
    (setq mew-complete-window-config nil)))

;;;
;;; Folder
;;;

(defvar mew-input-folder-hist nil)

(defun mew-input-folder (default)
  (let ((folder))
    (mew-input-clear)
    (setq mew-input-complete-function (function mew-complete-folder))
    (setq folder (read-from-minibuffer (format "Folder name (%s): " default)
				       "+"
				       mew-input-map
				       nil
				       'mew-input-folder-hist))
    (directory-file-name 
     (if (or (string= folder "") (string= folder "+"))
 	 default
       folder))))

(defun mew-input-folders (default &optional prompt)
  (let (form folders)
    (if prompt
	(progn
	  (setq form "Folder name : ")
	  (setq default prompt)
	  )
      (setq form (format "Folder name (%s): " default))
      (setq prompt "+")
      )
    (mew-input-clear)
    (setq mew-input-complete-function (function mew-complete-folder))
    (setq folders (read-from-minibuffer form
					prompt
					mew-input-map
					nil
					'mew-input-folder-hist))
    (if (or (string= folders "") (string= folders "+"))
	(setq folders default))
    (mapcar
     (function directory-file-name) 
     (mew-header-split
      (mew-header-syntax folders) ?,))))

;;;
;;; Address
;;;

(defvar mew-input-address-hist nil)

(defun mew-input-address (prompt)
  (mew-input-clear)
  (setq mew-input-complete-function (function mew-complete-address))
  (read-from-minibuffer (concat prompt " ")
			""
			mew-input-map
			nil
			'mew-input-address-hist))

(defun mew-input-address2 (prompt default)
  (mew-input-clear)
  (setq mew-input-complete-function (function mew-complete-address))
  (let (ret)
    (setq ret (read-from-minibuffer 
	       (format prompt default)
	       ""
	       mew-input-map
	       nil
	       'mew-input-address-hist))
    (if (string= ret "") default ret)))

;;;
;;; Pick pattern
;;;

(defvar mew-input-pick-pattern-hist nil)

(defun mew-input-pick-pattern ()
  (mew-input-clear)
  (setq mew-input-complete-function (function mew-complete-pick-pattern))
  (let ((keymap (copy-keymap mew-input-map)) ret)
    (define-key keymap " " nil)
    (setq ret
	  (mew-pick-canonicalize-pattern
	   (mew-pick-macro-expand-string
	    (read-from-minibuffer "pick pattern: "
				  mew-pick-default-field
				  keymap
				  nil
				  'mew-input-pick-pattern-hist))))
    (mew-decode-syntax-delete)
    ret))

;;;
;;; Sort key
;;;

(defvar mew-input-sort-key-hist nil)

(defun mew-input-sort-key ()
  (mew-input-clear)
  (setq mew-input-complete-function (function mew-complete-sort-key))
  (let* ((field:mode (read-from-minibuffer
		      (format "Sort by (%s)? : " mew-sort-default-key)
		      ""
		      mew-input-map
		      nil 
		      'mew-input-sort-key-hist))
	 field mode)
    (if (or (null field:mode) (equal field:mode ""))
	(setq field:mode mew-sort-default-key))
    (setq field (car (mew-header-split field:mode ?:)))
    (setq mode  (or (car (cdr (mew-header-split field:mode ?:)))
		    (cdr (assoc field mew-sort-key-alist))
		    "text"))
    (cons field mode)))

;;;
;;; Remote file
;;;

(defvar mew-input-rfile-hist nil)

(defun mew-input-rfile (prompt) ;; prompt="To:"
  (mew-input-clear)
  (setq mew-input-complete-function (function mew-complete-rfile))
  (read-from-minibuffer
   (concat prompt " ")
   ""
   mew-input-map
   nil
   'mew-input-rfile-hist))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Emacs primitive completion
;;;

;;;
;;; Range
;;;

(defun mew-input-range (folder &optional range)
  "Return (range erase-update)."
  ;; for the case when parts are expanded in the bottom of the folder
  (let* ((pair (mew-assoc-match2 folder mew-range-alist 0))
	 (default (or (cdr pair) "update")) ;; just in case
	 ret)
    (if (and mew-ask-range (not range))
	(setq range
	      (completing-read (format "Range (%s): " default)
			       (mapcar
				(lambda (x) (cons x x))
				mew-input-range-list))))
    (if (or (string= range "") (not range))
	(setq range default))
    (if (not (string-match "^[0-9a-zA-Z]" range))
	(error "Illegal range: %s" range))
    (cond
     ;; range is other than "update"
     ((not (string= range "update"))
      (setq ret (list range 'erase))) ;; non-update, erase it
     ;; update
     ((get-buffer folder)
      (setq ret (mew-update-range)))
     ;; update but folder doesn't exist in Emacs. 
     (t (setq ret (list "all" 'update))) ;; no need to erase
     )
    (mew-decode-syntax-delete)
    ret))

(defun mew-update-range ()
  (save-excursion
    (goto-char (point-max))
    (if (bobp)
	(list "all" 'update) ;; buffer is empty. no need to erase
      (forward-line -1)
      (mew-summary-goto-message)
      (list 
       (concat
	(int-to-string (1+ (string-to-int (mew-summary-message-number))))
	"-" 
	"last")
       'update) ;; this is update!
      )))

;;;
;;; File
;;;

(defun mew-input-file-name (&optional prompt default)
  (let ((msg (or prompt "File: "))
	(use-dialog-box nil)
	file)
    (cond
     ((null default)
      (setq file mew-home))
     ((or (string-match (format "^[~%s]" mew-path-separator) default)
        ;; allow drive letter -- "^\\([A-Za-z]:\\|[~%s]\\)"
        (string-match (format "^[A-Za-z]:%s.+" mew-path-separator) default))
      (setq file default))
     (t
      (setq file (concat mew-home default))
      )
     )
    (expand-file-name (read-file-name msg file file))
    ))

(defun mew-input-directory-name (&optional default)
  (let ((dir (expand-file-name (read-file-name "Directory : " default nil t))))
    (if (file-directory-p dir)
	dir
      (message "%s is not directory" dir)
      (sit-for 1)
      (mew-input-directory-name)
      )
    ))

;;;
;;; String
;;;

(defun mew-input-string (prompt subdir default)
  (let ((input (read-string (format prompt subdir default) "")))
    (if (string= input "") default input))
  )

;;;
;;; Type
;;;

(defun mew-input-type (prompt filename default type-list)
  (let ((completion-ignore-case t)
	(type))
    (setq type (completing-read
		(format prompt filename default)
		(mapcar (lambda (x) (cons x x)) type-list)
		nil
		t  ;; not require match
		""))
    (if (string= type "") default type)
    ))

;;;
;;; Config
;;;

(defun mew-input-config (default)
  (let ((config))
    (setq config (completing-read
		  (format "Config value (%s): "
			  (or default mew-config-default))
		  (mapcar (lambda (x) (cons x x)) mew-config-list)
		  nil nil nil))
    (if (string= config "")
	(or default mew-config-default)
      config)
    ))

;;;
;;;
;;;

(defun mew-input-general (prompt alist &optional require-match initial)
  (let* ((completion-ignore-case t)
	 (question (if initial (format "%s (%s) : " prompt initial)
		     (format "(%s) : " prompt)))
	 (value (completing-read question alist nil require-match nil)))
    (if (and initial (string= value "")) initial value)
    ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; password function
;;;

(defun mew-input-passwd (prompt)
  (let ((pass nil)
	(c 0)
	(echo-keystrokes 0)
	(ociea cursor-in-echo-area)
	(inhibit-input-event-recording t))
    (unwind-protect
	(progn
	  (setq cursor-in-echo-area 1)
	  (while (and (/= c ?\r) (/= c ?\n) (/= c ?\e) (/= c 7)) ;; ^G
	    (message "%s%s"
		     prompt
		     (make-string (length pass) ?.))
	    (setq c (read-char-exclusive))
	    (if (char-equal c ?\C-u)
		(setq pass "")
	      (if (and (/= c ?\b) (/= c ?\177))
		  (setq pass (concat pass (char-to-string c)))
		(if (> (length pass) 0)
		    (setq pass (substring pass 0 -1))))))
	  (setq cursor-in-echo-area -1)
	  )
      (setq cursor-in-echo-area ociea)
      nil)
    (message "")
    (sit-for 0)
    (substring pass 0 -1)
    ))

(provide 'mew-minibuf)

;;; Copyright Notice:

;; Copyright (C) 1997, 1998 Mew developing team.
;; All rights reserved.

;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions
;; are met:
;; 
;; 1. Redistributions of source code must retain the above copyright
;;    notice, this list of conditions and the following disclaimer.
;; 2. Redistributions in binary form must reproduce the above copyright
;;    notice, this list of conditions and the following disclaimer in the
;;    documentation and/or other materials provided with the distribution.
;; 3. All advertising materials mentioning features or use of this software
;;    must display the following acknowledgement:
;;       This product includes software developed by 
;;       Mew developing team and its contributors.
;; 4. Neither the name of the team nor the names of its contributors
;;    may be used to endorse or promote products derived from this software
;;    without specific prior written permission.
;; 
;; THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS'' AND
;; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
;; PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE TEAM OR CONTRIBUTORS BE
;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
;; OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
;; IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

;;; mew-minibuf.el ends here
