;;
;; $Id: paranoid-backup.el,v 1.3 1996/08/20 15:34:57 ejb Exp $
;; $Source: /home/ejb/elisp/q/RCS/paranoid-backup.el,v $
;; $Author: ejb $
;;
;; Minor mode for paranoid-backup
;; When this mode is in effect, every safe of this buffer generates a
;; new backup. 
;;

(provide 'paranoid-backup)

(defvar paranoid-backup-mode nil)
(make-variable-buffer-local 'paranoid-backup-mode)

;;
;; This variable is used to keep track of whether each of several variables
;; are buffer-local and what their original values were.  This is used
;; so that we set then upon entering the mode and restore them upon
;; leaving the mode.  Each element of this association list's car is
;; a variable name and cdr is a cons cell whose car is whether
;; the variable was local to the buffer and whose cdr was the variable's
;; value upon entry to the mode.
;;
(defvar paranoid-backup-save-vars nil)
(make-variable-buffer-local 'paranoid-backup-save-vars)

(defun paranoid-backup-local-set (var val)
  "Set VAR to VAL keeping information about its previous status."
  (let ((save-info (cdr (assq var paranoid-backup-save-vars))))
    (if (null save-info)
	(progn
	  (setq paranoid-backup-save-vars
		(cons (cons var (cons nil nil))
		      paranoid-backup-save-vars)
		)
	  (setq save-info (cdr (assq var paranoid-backup-save-vars)))
	  )
      )
    (setcar save-info (local-variable-p var))
    (setcdr save-info (eval var))
    (make-local-variable var)
    (set var val)
    )
  )

(defun paranoid-backup-local-restore (var)
  "Restore VAR to its previous local-variable status and value"
  (let ((save-info (cdr (assq var paranoid-backup-save-vars))))
    (if save-info
	(progn
	  (if (null (car save-info))
	      (kill-local-variable var)
	    (set var (cdr save-info))
	    )
	  )
      )
    )
  )

(defun paranoid-backup-backup-buffer ()
  ;; Hopefully this documented variable's meaning will not change.
  ;; Setting this to nil here definitely has the effect of forcing a
  ;; backup on next save (this save) in emacs 19.32 and 19.33.
  (setq buffer-backed-up nil)
  nil
  )

(defun paranoid-backup-setup (arg)
  "Set up upon entering or clean up upon leaving paranoid-backup mode."
  (if arg
      (progn
	;;
	;; Do any other minor mode initialization here
	;;

	(paranoid-backup-local-set 'kept-old-versions 2)
	(paranoid-backup-local-set 'kept-new-versions 4)
	(paranoid-backup-local-set 'delete-old-versions t)
	(paranoid-backup-local-set 'version-control t)
	(paranoid-backup-local-set 'make-backup-files t)
	(paranoid-backup-local-set 'backup-inhibited nil)
	(add-hook 'local-write-file-hooks 'paranoid-backup-backup-buffer)
	)
    ;; else
    ;;
    ;; Do any other minor cleanup here
    ;;
    (remove-hook 'local-write-file-hooks 'paranoid-backup-backup-buffer)
    )
  )

(defun paranoid-backup-mode (arg)
  "Toggle on paranoid-backup mode."
  (interactive "P")
  (if (null arg)
      (setq paranoid-backup-mode (not paranoid-backup-mode))
    (setq paranoid-backup-mode t))
  (if paranoid-backup-mode
      (progn
	;; Turn on minor mode
	(or (assq 'paranoid-backup-mode minor-mode-alist)
	    (setq minor-mode-alist
		  (append '((paranoid-backup-mode " paranoid-backup"))
			  minor-mode-alist)
		  )
	    )

	(paranoid-backup-setup t)
	)
    ;; else
    (mapcar (lambda (elem) (paranoid-backup-local-restore (car elem)))
	    paranoid-backup-save-vars
	    )
    (setq paranoid-backup-save-vars nil)
    (paranoid-backup-setup nil)
    )
  (force-mode-line-update)
  )
