;;; Zastai.el -- Some of my own emacs stuff

;; We need custom (or our own version of it)
;; This bit of code was shamefully stolen from po-mode.el
(eval-and-compile
  (condition-case ()
      (require 'custom)
    (error nil))
  (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
      nil
    (defmacro defgroup (&rest args)
      nil)
    (defmacro defcustom (var value doc &rest args)
      (` (defvar (, var) (, value) (, doc))))))

(defgroup zastai nil
  "A list of variables used by Zastai's functions."
  :tag "Zastai's Customization"
  :group 'local
  )

(defun zastai-unix-to-dos-buffer ()
  "Convert the current buffer to MS-DOG style text. 
This means: append ^M to each line.
Rendered mostly obsolete by Emacs 20.x"
  (interactive)
  (save-excursion
    (message "Dossifying buffer...")
    (goto-char (point-min))
    (while (and (search-forward-regexp "$" nil t) (< (point) (point-max)))
      (replace-match "\015") (forward-char))
    (message "Done!")
  )
)

(defun zastai-dos-to-unix-buffer ()
  "Convert the current buffer to Unix style text. 
This means: strip ^M from each line and ^Z from end of file (if present).
Rendered mostly obsolete by Emacs 20's coding system support."
  (interactive)
  (save-excursion
    (message "Unixifying buffer...")
    (goto-char (point-min))
    (while (and (search-forward-regexp "\015$" nil t) (< (point) (point-max)))
      (replace-match "") (forward-char))
    (goto-char (point-max))
    (backward-char)
    (if (looking-at "\032") (delete-char 1) ;strip ^Z
      )
    (message "Done!")
  )
)

(defcustom zastai-calculator "doscalc"
  "*Program to be run by `zastai-run-calculator'."
  :type 'string
  :tag "Calculator Program"
  :group 'zastai
)

(defun zastai-run-calculator ()
  "Runs the program specified in `zastai-calculator'."
  (interactive)
  (call-process zastai-calculator nil nil nil)
)

(defcustom zcd-verbose nil
  "*Controls whether or not `zcd' will print info about the CD it plays.
This also affects `zastai-play-cd' and `zastai-stop-cd'."
  :type 'boolean
  :tag "CD Information"
  :group 'zastai
)

(defcustom zastai-cd-info-inifile "~/zcd.ini"
  "*The file that contains information about Audio CDs.
This should be in Win95's cdplayer.ini format."
  :type 'string
  :tag "CD Information File"
  :group 'zastai
)

(defun zcd-info (&optional track extra-info)
  "Prints information about the Audio CD in the first CD drive.
With a prefix argument, gives information about that track."
  (let ((info-string nil) (serial nil) (buf (generate-new-buffer "*cd-info*")))
    (if (not (call-process "cdserial" nil buf nil)) nil
      (set-buffer buf)
      (setq serial (buffer-substring-no-properties 1 (point)))
      (delete-region 1 (point))
      (if (numberp track)
	  (call-process "ini" nil buf nil
			(expand-file-name zastai-cd-info-inifile)
			serial (number-to-string (- track 1)) "Unknown Track")
	  (call-process "ini" nil buf nil
			(expand-file-name zastai-cd-info-inifile)
			serial "Artist" "Unknown Artist")
	  (insert
	   (if (string= (buffer-substring-no-properties (- (point) 1) (point))
			"s") "' " "'s "))
	  (call-process "ini" nil buf nil
			(expand-file-name zastai-cd-info-inifile)
			serial "Title" "Unknown Album")
	)
      (setq info-string (buffer-substring-no-properties 1 (point)))
      )
    (kill-buffer buf)
    (cond ((numberp track)
	   (if (null info-string)
	       (setq info-string (concat "Track " (number-to-string track)))))
	  (t (if (null info-string) (setq info-string "Audio CD"))))
    (cond ((eq extra-info 'play)
	   (if (numberp track)
	       (message "Playing CD (starting at '%s')..." info-string)
	     (message "Playing %s..." info-string)))
	  ((eq extra-info 'stop)
	   (message "Stopping playback of %s..." info-string))
	  (t (if (numberp track)
		 (message "Track %d: %s" track info-string)
	       (message "Audio CD: %s" info-string))))
    )
)

(defun zastai-cd-info (&optional track)
  "Prints information about the Audio CD in the first CD drive.
With a prefix argument, gives information about that track."
  (interactive "P")
  (zcd-info track)
)

(defun zcd (&optional track)
  "Runs 'zcd' to play cd audio.
The track can be a prefix argument; if not given it is prompted for.
If track is given, playback starts at that track and stops at the end of the
disk."
  (interactive "NPlay from which track? ")
  (if zcd-verbose (zcd-info track 'play))
  (call-process "zcd" nil nil nil "-x" (if track (concat "--track=" track) ""))
)

(defun zastai-play-cd (&optional track)
  "Runs `zcd' to play cd audio.
The track can be specified as a prefix argument.
If track is given, playback starts at that track and stops at the end of the
disk."
  (interactive "P")
  (if zcd-verbose (zcd-info track 'play))
  (call-process "zcd" nil nil nil "-x" (if track (concat "--track=" track) ""))
)

(defun zastai-stop-cd ()
  "Runs `zcd' to stop cd audio."
  (interactive)
  (if zcd-verbose (zcd-info nil 'stop))
  (call-process "zcd" nil nil nil "-kx")
)

;; Key bindings and a menu for my functions
(define-key global-map "\C-cz" (make-sparse-keymap))
(define-key global-map "\C-czc" 'zastai-run-calculator)
(define-key global-map "\C-czx" 'zastai-dos-to-unix-buffer)
(define-key global-map "\C-czd" 'zastai-unix-to-dos-buffer)
(define-key global-map "\C-czp" 'zastai-play-cd)
(define-key global-map "\C-czi" 'zastai-cd-info)
(define-key global-map "\C-czs" 'zastai-stop-cd)
(define-key global-map "\C-czm" 'mpuz)
(define-key global-map "\C-czg" 'gomoku)
(define-key global-map [menu-bar zastai]
  (cons "Zastai" (make-sparse-keymap "Zastai")))
(define-key global-map [menu-bar zastai go]
  '("Gomoku"         . gomoku))
(define-key global-map [menu-bar zastai mpuz]
  '("Mult. Puzzle"   . mpuz))
(define-key global-map [menu-bar zastai separator]
  '("--"    . nil))
(define-key global-map [menu-bar zastai cdinfo]
  '("CD Info"        . zastai-cd-info))
(define-key global-map [menu-bar zastai stopcd]
  '("Stop CD"        . zastai-stop-cd))
(define-key global-map [menu-bar zastai playcd]
  '("Play CD"        . zastai-play-cd))
(define-key global-map [menu-bar zastai calculator]
  '("Run Calculator" . zastai-run-calculator))
(define-key global-map [menu-bar zastai dossify]
  '("Dossify Buffer" . zastai-unix-to-dos-buffer))
(define-key global-map [menu-bar zastai unixify]
  '("Unixify Buffer" . zastai-dos-to-unix-buffer))

;; Define function keys to actually do something
;; Function Key  1
(define-key global-map [S-f1]      'command-apropos)
(define-key global-map [C-f1]      'info)
;; Function Key  2
(define-key global-map [f2]        'find-tag)
(define-key global-map [S-f2]      'find-tag-other-window)
(define-key global-map [C-f2]      'find-tag-other-frame)
;; Function Key  3
(define-key global-map [f3]        'isearch-forward)
(define-key global-map [S-f3]      'isearch-backward)
(define-key global-map [C-f3]      'isearch-forward-regexp)
(define-key global-map [C-S-f3]    'isearch-backward-regexp)
;; Function Key  4
(define-key global-map [f4]        'replace-string)
(define-key global-map [C-f4]      'replace-regexp)
;; Function Key  5
(define-key global-map [f5]        'query-replace)
(define-key global-map [C-f5]      'query-replace-regexp)
;; Function Key  6
(define-key global-map [f6]        'other-window)
(define-key global-map [C-f6]      'switch-to-buffer)
;; Function Key  7
(define-key global-map [f7]        'describe-variable)
(define-key global-map [S-f7]      'describe-function)
(define-key global-map [C-f7]      'describe-key)
(define-key global-map [S-C-f7]    'where-is)
(define-key global-map [M-f7]      'describe-face)
(define-key global-map [S-M-f7]    'describe-coding-system)
(define-key global-map [C-M-f7]    'describe-input-method)
(define-key global-map [S-C-M-f7]  'describe-language-environment)
;; Function Key  8
(define-key global-map [f8]        'customize)
(define-key global-map [S-f8]      'customize-group)
(define-key global-map [C-f8]      'customize-variable)
(define-key global-map [S-C-f8]    'customize-face)
(define-key global-map [M-f8]      'customize-apropos)
;; Function Key  9
(define-key global-map [f9]        'delete-window)
(define-key global-map [C-f9]      'delete-other-windows)
(define-key global-map [M-f9]      'delete-frame)
;; Function Key 10
(define-key global-map [f10]       'suspend-emacs)
(define-key global-map [C-f10]     'save-buffers-kill-emacs)
(define-key global-map [C-M-f10]   'kill-emacs)
;; Function Key 11
(define-key global-map [f11]       'font-lock-fontify-buffer)
(define-key global-map [S-f11]     'font-lock-fontify-block)
;; Function Key 12
(define-key global-map [f12]       'kill-buffer)
(define-key global-map [S-f12]     'kill-paragraph)
(define-key global-map [C-f12]     'kill-rectangle)

; Grow/Shrink window
(define-key global-map [C-kp-add]      'enlarge-window)
(define-key global-map [C-kp-subtract] 'shrink-window)

;; Various bindings
(define-key global-map [C-xg] 'goto-line)

;; Use keypad enter for newline
;; This is handy in Lisp Interaction buffers, for instance
(define-key function-key-map [kp-enter] [10])

(provide 'zastai)
