; Functions to add and subtract clock-time lists of the form
;    (hours minutes [AM | PM])
; Second args can optionally be in the form of integer minute values.
;

(defun caddr (x) (car (cdr (cdr x))))

(defun add-time (t1 t2)
"Add the hour-minute time value T2 to T1.  The T1 time value is a list of the
form
    (hours minutes [AM | PM]).
The T2 value is either a list of the form
    (hours minutes)
or an integer number of minutes.  The result is a list of the form
    (hours minutes [AM | PM] [[+ | -] day(s)]).
The +/- day(s) value is present if the result roles over to a previous or later
day."
    (interactive "xt1: 
xt2: ")

    (let* ((adjusted-t2 (if (integerp t2) (minutes-to-time t2) t2))
	   (raw-hours (+ (car t1) (car adjusted-t2)))
	   (raw-minutes (+ (cadr t1) (cadr adjusted-t2)))
	   (am-or-pm (caddr t1))
	   (actual-hours (+ raw-hours (/ raw-minutes 60)))
	   (actual-minutes (% raw-minutes 60)))

	(let ((value (list actual-hours actual-minutes)))
	    (if (interactive-p)
		(message (substring (pp value) 0 -1))
	    )
	    value
	)
    )
)

(defun minutes-to-time (minutes)
"Convert the given integer minutes value to a time value of the form
 (hours minutes)."
    (interactive "nMinutes value: ")
    (let ((value (list (/ minutes 60) (% minutes 60))))
	(if (interactive-p)
	    (message (substring (pp value) 0 -1))
	)
	value
    )
)

(defun time-to-minutes (time)
"Convert the given hours-minutes time value to integer minutes."
    (interactive "x(hours minutes) time value: ")
    (let ((value (+ (* (car time) 60) (cadr time))))
	(if (interactive-p)
	    (message (int-to-string value))
	)
	value
    )
)

(defun subtract-time (t1 t2)
"Subtract the hour-minute time value T2 from T1.  See function add-time for
description of argument and return value formats."
    (interactive "xt1: 
xt2: ")

    (let* ((value
	   (if (integerp t2)
	       (add-time t1 (- t2))
	       (add-time t1 (list (- (car t2)) (- (cadr t2))))
	    ))
	   (adjusted-value
	    (if (< (cadr value) 0)
		(list (+ (car value) (1- (/ (cadr value) 60)))
		      (- 60 (- (% (cadr value) 60))))
	        value
	    )))

	(if (interactive-p)
	    (message (substring (pp adjusted-value) 0 -1))
	)
	adjusted-value
    )
)

; Quickie tests: 
(defun test-time-funcs ()
    (interactive)
    (let* ((result1 (add-time '(3 45) 100))
	   (result2 (subtract-time result1 100))
	   (result3 (time-to-minutes (subtract-time result1 '(3 45))))
	   (result4 (time-to-minutes (subtract-time '(5 25) '(1 52))))
	   (result (list result1 result2 result3 result4)))

	(message (concat "Expected result: ((5 25) (3 45) 100 213)  "
			 "Actual result: "
			     (concat "(" (substring (pp result1) 0 -1) " "
					 (substring (pp result2) 0 -1) " "
					 (int-to-string result3)  " "
					 (int-to-string result4)
				     ")")))
    )
)

; Fahrenheit-to-celius and vice versa conversions.
(defun f2c (f-degrees)
    (interactive "NDegrees Fahrenheit: ")
    (* (/ (- f-degrees 32.0) 9.0) 5.0)
)
(defun c2f (c-degrees)
    (interactive "NDegrees Fahrenheit: ")
    (+ (* (/ c-degrees 5.0) 9.0) 32.0)
)
(defun c2f-table ()
    (let ((x 0) (table nil))
        (while (<= x 50)
	    (setq table (append table (list (c2f x))))
	    (append-string-to-buffer "c2f-table" (number-to-string x))
	    (setq x (1+ x))
	)
    table
    )
)

(defun t1 (x &optional y)
    (interactive)
    (if (null y)
	(message "Null y")
        (message (int-to-string y))
    )
)