;;; rsi-brk.el --- Periodic R.S.I. typing breaks

;; Copyright (C) 2006-2011 Davin Pearson

;; Author/Maintainer: m4_davin_pearson
;; Keywords: Current Function method
;; Version: 1.0

;;; Commentary:

;; This file is not part of GNU Emacs.

;; This code provides compulsory periodic R.S.I. (Repetitive Strain
;; Injury) typing breaks.

;;; m4_limitation_of_warranty

;;; m4_install_instructions(rsi-brk)

;;; Known Bugs:

;; None so far!

;;; Code:

(require 'd-time)

(defvar rsi-period (* 5 60)
  "The time (in seconds) between the mandatory rsi-breaks.")

(defvar rsi-break  10
  "The time (in seconds) of the mandatory rsi-breaks.")

(defvar rsi-last-break nil
  "String containing the time of the last rsi-break.")

(defvar rsi-keystroke-count 60
  "How many keystrokes per minute")

(defun rsi-start-timer ()
  "Starts the rsi-break system in operation.  Cannot call this twice without errors."
  (if (boundp 'rsi-timer)
      (cancel-timer rsi-timer))
  (setq rsi-timer (run-with-timer 0 rsi-period 'rsi-timer-function))
  (setq rsi-last-plugged-in (current-time-string))
  (add-hook 'post-command-hook 'rsi-increment-keycount)
  )

(defun rsi-stop-timer ()
  "Stops the rsi-break system."
  (cancel-timer rsi-timer)
  (remove-hook 'post-command-hook 'rsi-increment-keycount))



(setq rsi-on nil)
;; (rsi-timer-function)
;; (setq rsi-keystroke-count 0)
(defun rsi-timer-function ()
  (interactive)
  (let ((timer-idle-list nil)
        (keys-per-minute (/ rsi-keystroke-count (/ rsi-period 60.0)))
        (d-message-on t))
    (let* ((message-log-max nil)
           (pad-size (max 0 (/ (- (frame-width) (+ (* 2 (length "TYPING BREAK..."))
                                                   (length "12345  keys-per-minute")
                                                   (length "abcdefgh")
                                                   )) 2)))
           (padding (make-string pad-size ? )))
      (setq rsi-last-break (current-time))
      (when (and rsi-on (> keys-per-minute 0))
        (let ((i rsi-break))
          (while (> i 0)
            ;;(if (< (- rsi-break 2) i)
            (let ((visible-bell t))
              (beep))
            ;;(let ((visible-bell nil))
            ;;  (beep))
            (let ((j 8))
              (while (> j 0)
                (message (format (concat
                                  "%s %3d"
                                  padding
                                  "%5d  keys-per-minute"
                                  padding
                                  "%3d %s")
                                 (cond ((= 0 (mod j 2))
                                        "TYPING BREAK...")
                                       (t
                                        "               "))
                                 i keys-per-minute i
                                 (cond ((= 0 (mod j 2))
                                        "...TYPING BREAK")
                                       (t
                                        "               "))))
                (sleep-for 0.1)
                (decf j)))
            (decf i))
          (message ""))))
    (setq rsi-keystroke-count 0)
    (setq rsi-on t)
    (if (and rsi-log-time-worked (> keys-per-minute 0))
        (progn
          (message "Last rsi-brk commencing at %s keys-per-minute=%d time to get off computer!" (d-time--decode-time-readable) keys-per-minute)
          (rsi-log (format "%s %d" (d-time--decode-time-readable rsi-last-break) keys-per-minute)))
      (message "Last rsi-brk commencing at %s keys-per-minute=%d"
               (d-time--decode-time-readable rsi-last-break)
               keys-per-minute)
      )
    )
  )

(defvar rsi-log-time-worked nil
  "Whether or not to record hours worked")

(defvar rsi-log-file (concat "~/rsi-log-"
                             (d-time--get-stamp d-emacs-start-time)
                             ".txt")
  "Log file #1 for recording rsi-brk timestamps")

(defvar rsi-log-file-2 (concat "~/rsi-hours-worked-"
                               (d-time--get-stamp d-emacs-start-time)
                               ".txt")
  "Log file #2 for recording hours worked")

;; (setq str "abc")
(defun rsi-log (str)
  (save-excursion
    (setq buf (find-file rsi-log-file))
    (read-only-mode -1)
    (end-of-buffer)
    (insert str "\n")
    (let ((d-message-on t))
      (message str))
    (save-buffer 'NO-QUESTIONS)
    (kill-buffer buf))
  (if (fboundp 'd-speedbar)
      (d-speedbar)))

;;; (setq line  "20131202-194612")
;;; (setq line2 "20131202-194730")
(defun rsi-compute-time ()
  (interactive)
  (save-excursion
    (let (line t1 start-time done line2 t2 buf)
      (progn
        (progn
          (find-file rsi-log-file-2)
          (read-only-mode -1)
          (erase-buffer))
        (progn
          (find-file rsi-log-file)
          (read-only-mode -1)
          (goto-char (point-min))
          ;;             Y    Y    Y    Y    M    M    D    D     H    H    M    M    S    S
          (flush-lines "^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][ \t]+0[ \t]*$")
          )
        (goto-char (point-min))
        ;;(setq line "20131202-204000")
        (setq line (d-time--current-line-as-string))
        (if (string= "" line)
            (setq done t)
          (setq line (substring line 0 (length "YYYYMMDD-HHMMSS")))
          (setq start-time (d-time--yyyymmdd-hhmmss-to-time line))
          (setq done nil)
          (setq count 0)
          ;; (setq line2 "20131202-204210")
          (while (not done)
            (incf count)
            (setq line (d-time--current-line-as-string))
            (if (string= "" line)
                (setq done t)
              (setq line (substring line 0 (length "YYYYMMDD-HHMMSS")))
              (setq t1 (d-time--yyyymmdd-hhmmss-to-time line))
              (forward-line 1)
              (beginning-of-line)
              (setq line2 (d-time--current-line-as-string))
              (if (string= "" line2)
                  (setq done t)
                (setq line2 (substring line2 0 (length "YYYYMMDD-HHMMSS")))
                (setq t2 (d-time--yyyymmdd-hhmmss-to-time line2))
                (if (> (seconds-of-time-difference t1 t2) (* 2 rsi-period))
                    (save-excursion
                      (find-file rsi-log-file-2)
                      (read-only-mode -1)
                      (goto-char (point-max))
                      (insert (format "%s %3d minutes t1=%s, t2=%s\n"
                                      (d-time--get-stamp start-time)
                                      (/ (seconds-of-time-difference start-time t1) 60)
                                      (d-time--get-stamp t1)
                                      (d-time--get-stamp t2)
                                      ))
                      (setq start-time t2)
                      ;;(debug "Alpine")
                      )
                  ))))
          (save-excursion
            (find-file rsi-log-file-2)
            (read-only-mode -1)
            (goto-char (point-max))
            (insert (format "%s %3d minutes t1=%s, t2=%s\n"
                            (d-time--get-stamp start-time)
                            (/ (seconds-of-time-difference start-time t1) 60)
                            (d-time--get-stamp t1)
                            (d-time--get-stamp t2)))))
        ;;(debug "Alpine")
        (save-excursion
          (setq buf (find-file rsi-log-file-2))
          ;;(read-only-mode -1)
          (save-buffer)
          (kill-buffer buf)
          (message "Time to get off computer!")
          )
        ) ;; END PROGN!
      )
    )
  )

(setq rsi-last-command-keys nil)

(defun rsi-increment-keycount ()
  (let ((tck (this-command-keys)))
    (if (not (equal rsi-last-command-keys (this-command-keys)))
        (setq rsi-keystroke-count (+ rsi-keystroke-count (length (this-command-keys)))))
    (setq rsi-last-command-keys tck)))

(byte-compile 'rsi-increment-keycount)
;;(symbol-function 'rsi-increment-keycount)

(if (not noninteractive)
    (rsi-start-timer))

;;(shell-command "rm -v ~/rsi-log-*.el")

(provide 'rsi-brk)
;;; rsi-brk.el ends here
