;;; temperature.el --- Show the current temperature in the modeline

;; Copyright (C) 2009  Mark Triggs

;; Author: Mark Triggs <mtriggs@nla.gov.au>

;; This file 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 3, or (at your option)
;; any later version.

;; This file 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 GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

(defun temperature-shell-command-to-string (callback cmd &rest args)
  (lexical-let ((proc (apply 'start-process "cmd" nil cmd args))
                (output "")
                (fn callback))
    (set-process-sentinel proc (lambda (proc str)
                                 (funcall fn output)))
    (set-process-filter proc (lambda (proc str)
                               (setq output (concat output str))))))


(defun temperature-update ()
  (temperature-shell-command-to-string
   (lambda (str)
     (let ((bits (split-string str "\0")))
       (setq *current-temperature* (car (read-from-string (car bits))))
       (setq *current-forecast* (cadr bits)))
     (force-mode-line-update))
   "temperature.pl"))


(defvar *temperature-colours*
  '(("blue" . "#0000FF")
    ("dark-blue" . "#0000CC")
    ("orange" . "#FF9900")
    ("dark-orange" . "#E86400")
    ("red" . "#FF0000")
    ("dark-red" . "#C40000")))


(defun weather-dot (colour)
  "Return an XPM string representing a dot whose colour is COLOUR."
  (format "/* XPM */
static char * weather_dot[] = {
\"18 13 4 1\",
\" 	c None\",
\".	c #000000\",
\"+	c %s\",
\"c	c %s\",
\"                  \",
\"       .....      \",
\"      .ccccc.     \",
\"     .cc+++cc.    \",
\"    .cc+++++cc.   \",
\"    .c+++++++c.   \",
\"    .c+++++++c.   \",
\"    .c+++++++c.   \",
\"    .cc+++++cc.   \",
\"     .cc+++cc.    \",
\"      .ccccc.     \",
\"       .....      \",
\"                  \"};"
	  (cdr (assoc colour *temperature-colours*))
	  (cdr (assoc (concat "dark-"colour) *temperature-colours*))))

(defvar *temperature-ranges*
  `(((lambda (temp) (< temp 20)) . ,(weather-dot "blue"))
    ((lambda (temp) (< temp 30)) . ,(weather-dot "orange"))
    ((lambda (temp) t) . ,(weather-dot "red"))))

(defun temperature-icon (temperature)
  (cdr (find-if (lambda (range) (funcall (first range) temperature))
           *temperature-ranges*)))


(defvar *current-temperature* 0)
(defvar *current-forecast* "")

(defun weather-show-on-modeline ()
  `("   "
    (:propertize "!"
                 help-echo ,*current-forecast*
                 display (image :type xpm
                                :data ,(temperature-icon *current-temperature*)
                                :ascent center))
    ,(format "%s%sC   "  *current-temperature*
             (if window-system
                 (string 176)
               "'"))))

(defvar *temperature-timer* nil)
(setq *temperature-timer* (run-at-time nil
                                       (* 15 60)
                                       'temperature-update))

(push '(:eval (weather-show-on-modeline)) global-mode-string)


(provide 'temperature)
;;; temperature.el ends here
