;;; xwem-worklog.el --- Worklog for XWEM.

;; Copyright (C) 2004 by Free Software Foundation, Inc.

;; Author: Zajcev Evgeny <zevlg@yandex.ru>
;; Created: Thu Feb 26 01:00:25 MSK 2004
;; Keywords: xwem
;; X-CVS: $Id: xwem-worklog.el,v 1.5 2004/05/14 12:36:54 lg Exp $

;; This file is part of XWEM.

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

;; XWEM 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 XEmacs; see the file COPYING.  If not, write to the Free
;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
;; 02111-1307, USA.

;;; Synched up with: Not in FSF

;;; Commentary:

;; Inspired by `worklog.el'.

;;; Code:

(eval-when-compile
  (require 'cl))

(require 'xwem-diagram)

(defstruct xwem-worklog-pause
  (type 'pause)                         ; type of pause, can be 'pause or 'list
  prefix-arg                            ; prefix arg, when entering pause
  pwin                                  ; xwin that shows pause stuff
  pbuf                                  ; buffer to render
  start-time
  end-time
  
  itimer                                ; content updater itimer
  )

(defstruct xwem-worklog-task
  name                                  ; task name
  times                                 ; list of cons cells in form (start-time . stop-time)
  (total-time '(0 0))                   ; total time spended on this task
  (today-time '(0 0))                   ; today's time spended on task
  
  last-comment                          ; last comment to this task
  )

(defgroup xwem-worklog nil
  "Group to customize xwem worklog."
  :prefix "xwem-worklog-"
  :group 'xwem)

(defcustom xwem-worklog-file "worklog"
  "*File to store xwem worklogs."
  :type 'file
  :group 'xwem-worklog)

(defcustom xwem-worklog-load-hook nil
  "*Hooks to run when worklog loaded."
  :type 'hook
  :group 'xwem-worklog)

(defcustom xwem-worklog-auto-continue nil
  "*Non-nil mean auto continue, when task started/stoped while in pause."
  :type 'boolean
  :group 'xwem-worklog)

(defcustom xwem-worklog-pause-dont-stop t
  "*Non-nil mean do not suspend current task when entering pause."
  :type 'boolean
  :group 'xwem-worklog)

(defcustom xwem-worklog-register-new-tasks t
  "*Non-nil mean register new tasks in `xwem-worklog-tasks-description'.
Task not registered if it is already in `xwem-worklog-tasks-description'."
  :type 'boolean
  :group 'xwem-worklog)

(defcustom xwem-worklog-auto-worklog-file nil
  "*Non-nil mean save changes all the time to `xwem-worklog-file'.
Note that `xwem-worklog-task-time-decrease' and
`xwem-worklog-task-time-increase' wont change file entries.
Seting value to non-nil make sure you have worklog package, placed at
http://www.emacswiki.org/elisp/worklog.el"
  :type 'boolean
  :group 'xwem-worklog)

(defcustom xwem-worklog-save-worklog-file-on-logout t
  "*Non-nil mean save current tasks state to `xwem-worklog-file', when you logout."
  :type 'boolean
  :group 'xwem-worklog)

(defcustom xwem-worklog-read-worklog-file-on-login t
  "*Non-nil mean read `xwem-worklog-file', when you login."
  :type 'boolean
  :group 'xwem-worklog)

(defcustom xwem-worklog-day-start 9
  "*Hour number when your workday starts."
  :type 'number
  :group 'xwem-worklog)

(defcustom xwem-worklog-day-ends 18
  "*Hour number when your workday ends."
  :type 'number
  :group 'xwem-worklog)

(defcustom xwem-worklog-logout-notify-period 5
  "*Period in minutes to notify, that your workday is end, and you need to logout."
  :type 'number
  :group 'xwem-worklog)

(defcustom xwem-worklog-logout-auto-period 60
  "*Period in minutes to autologout, after your workday is end."
  :type 'number
  :group 'xwem-worklog)

(defcustom xwem-worklog-login-notify-period 5
  "*Period in minutes to notify that your workday started."
  :type 'number
  :group 'xwem-worklog)

(defcustom xwem-worklog-login-stop-period 45
  "*Period in minites when login notifying stops."
  :type 'number
  :group 'xwem-worklog)

(defcustom xwem-worklog-pwin-background (face-background-name 'default)
  "*Color used as background color for xwem worklog pause window."
  :type '(restricted-sexp :match-alternatives ('nil xwem-misc-colorspec-valid-p))
  :group 'xwem-worklog)

(defcustom xwem-worklog-pwin-width 500
  "*Width of pause window."
  :type 'number
  :group 'xwem-worklog)

(defcustom xwem-worklog-pwin-height 500
  "*Height of xwem worklog pause window."
  :type 'number
  :group 'xwem-worklog)

(defcustom xwem-worklog-pwin-border-width 2
  "*Border width for xwem worklog pause window."
  :type 'number
  :group 'xwem-worklog)

(defcustom xwem-worklog-pwin-border-color "red4"
  "*Border color for xwem worklog pause window."
  :type '(restricted-sexp :match-alternatives ('nil xwem-misc-colorspec-valid-p))
  :group 'xwem-worklog)
  
(defcustom xwem-worklog-pause-cursor-shape 'X-XC-gumby
  "*Shape of cursor while in xwem worklog pause."
  :type (xwem-cursor-shape-choice)
  :group 'xwem-worklog)

(defcustom xwem-worklog-pause-cursor-foreground-color "#777777"
  "*Cursor's foreground color, while in xwem worklog pause."
  :type '(restricted-sexp :match-alternatives ('nil xwem-misc-colorspec-valid-p))
  :group 'xwem-worklog)

(defcustom xwem-worklog-pause-cursor-background-color nil
  "*Cursor's background color, while in xwem worklog pause."
  :type '(restricted-sexp :match-alternatives ('nil xwem-misc-colorspec-valid-p))
  :group 'xwem-worklog)

(defcustom xwem-worklog-use-diagram t
  "*Non-nil mean draw digram for today, when enter list mode."
  :type 'boolean
  :group 'xwem-worklog)

(defcustom xwem-worklog-diagram-type '3d
  "*Type of diagram to draw in list mode."
  :type '(choice (const :tag "3D Sectors" 3d)
                 (const :tag "Plain Sectors" plain))
  :group 'xwem-worklog)

(defcustom xwem-worklog-dockapp-diagram-type 'plain
  "*Type of diagram to draw in worklog dockapp."
  :type '(choice (const :tag "3D Sectors" 3d)
                 (const :tag "Plain Sectors" plain))
  :group 'xwem-worklog)

(defcustom xwem-worklog-load-hook nil
  "*Hooks to run when `xwem-worklog' loaded."
  :type 'hook
  :group 'xwem-worklog)

(defcustom xwem-worklog-task-start-hook nil
  "*Hooks to run when new task runned."
  :type 'hook
  :group 'xwem-worklog)

(defcustom xwem-worklog-login-hook nil
  "*Hooks to run when login."
  :type 'hook
  :group 'xwem-worklog)

(defcustom xwem-worklog-logout-hook nil
  "*Hooks to run when logout."
  :type 'hook
  :group 'xwem-worklog)

(defcustom xwem-worklog-tasks-description
  (list (vector "News/Mail/Web reading" (xwem-kbd "H-w") "blue")
        (vector "Info/man reading" (xwem-kbd "H-i") "cyan")
        (vector "Emacs lisping" (xwem-kbd "H-e") "yellow2")
        (vector "C for fun" (xwem-kbd "H-f") "tomato")
        (vector "C for profit" (xwem-kbd "H-p") "magenta")
        (vector "WorkProject" (xwem-kbd "H-c") "green2")
        (vector "Administrativa" (xwem-kbd "H-a") "lightblue")
        (vector "Smoke" (xwem-kbd "H-s") "red3")
        (vector "Nothing" (xwem-kbd "H-n") "gray80"))
  "Alist with elements in form (name . key)."
  :type 'alist
  :group 'xwem-worklog)

;;;###autoload
(xwem-define-prefix-command 'xwem-worklog-prefix t)
(defvar xwem-worklog-map (symbol-function 'xwem-worklog-prefix)
  "Keymap for xwem worklog (\\<xwem-global-map>\\[xwem-worklog-prefix]) commands.
Bindings:
\\{xwem-worklog-map}")

(define-key xwem-worklog-map (xwem-kbd "<tab>") 'xwem-worklog-login)
(define-key xwem-worklog-map (xwem-kbd "i") 'xwem-worklog-login)
(define-key xwem-worklog-map (xwem-kbd "<backspace>") 'xwem-worklog-logout)
(define-key xwem-worklog-map (xwem-kbd "o") 'xwem-worklog-logout)

(define-key xwem-worklog-map (xwem-kbd "b") 'xwem-worklog-begin-task)
(define-key xwem-worklog-map (xwem-kbd "s") 'xwem-worklog-end-task)
(define-key xwem-worklog-map (xwem-kbd "e") 'xwem-worklog-end-task)
(define-key xwem-worklog-map (xwem-kbd "p") 'xwem-worklog-pause)
(define-key xwem-worklog-map (xwem-kbd "l") 'xwem-worklog-task-list)

;; Scan throught `xwem-worklog-tasks-description' to install custom
;; keybindings.
(defun xwem-worklog-create-cmd (template)
  "Create symbol from TEMPLATE string."
  (let ((fsym (make-symbol (concat "xwem-worklog-custom-" (replace-in-string template " " "-")))))
    (fset fsym `(lambda ()
                  (interactive)
                  (xwem-worklog-begin-task ,template)))
    fsym))

(mapc (lambda (el)
        (define-key xwem-worklog-map (aref el 1) (xwem-worklog-create-cmd (aref el 0))))
      xwem-worklog-tasks-description)

(defvar xwem-worklog-pause-map
  (let ((map (make-sparse-keymap)))
    (set-keymap-default-binding map 'xwem-worklog-continue)

    (define-key map (xwem-kbd "-") 'xwem-worklog-task-time-decrease)
    (define-key map (xwem-kbd "+") 'xwem-worklog-task-time-increase)

    (define-key map (xwem-kbd "0") 'xwem-universal-digit)
    (define-key map (xwem-kbd "1") 'xwem-universal-digit)
    (define-key map (xwem-kbd "2") 'xwem-universal-digit)
    (define-key map (xwem-kbd "3") 'xwem-universal-digit)
    (define-key map (xwem-kbd "4") 'xwem-universal-digit)
    (define-key map (xwem-kbd "5") 'xwem-universal-digit)
    (define-key map (xwem-kbd "6") 'xwem-universal-digit)
    (define-key map (xwem-kbd "7") 'xwem-universal-digit)
    (define-key map (xwem-kbd "8") 'xwem-universal-digit)
    (define-key map (xwem-kbd "9") 'xwem-universal-digit)
    (define-key map xwem-universal-key 'xwem-universal-argument)

    (set-keymap-parents map (list xwem-worklog-map))
    map)
  "Keymap used when worklog in pause state.")

(defvar xwem-worklog-pause-cursor nil
  "Cursor used while in xwem worklog pause.")

(defvar xwem-worklog-pause-p nil
  "Non-nil when worklog in pause state.
Internal variable, do not modify!.")

(defvar xwem-worklog-current-task nil
  "Current task.")

(defvar xwem-worklog-task-list nil
  "List of tasks.")

(defvar xwem-worklog-pause-window-update-hook nil
  "Hooks called when updating pause window contents.
For internal usage only.")

(defstruct xwem-worklog-dockapp
  win
  update-itimer                         ; itimer to update worklog-dockapp

  ;; dockapp and sector geometry
  width height
  sector-width)

(defvar xwem-worklog-dockapp nil
  "Dockapp.")


(defun xwem-worklog-register-task (name &optional no-binding)
  "Register new task with NAME in `xwem-worklog-tasks-description'.
Query for keybinding unless NO-BINDING is non-nil."
  (let ((tal xwem-worklog-tasks-description))
    (while (and tal (not (string= (aref (car tal) 0) name)))
      (setq tal (cdr tal)))
    
    (unless tal
      (let ((key (and (not no-binding)
                      (xwem-read-key (format "Key for '%s' task: " name)))))
        (when key
          (setq key (events-to-keys (vector key)))
          (define-key xwem-worklog-map key (xwem-worklog-create-cmd name)))
        
        (setq xwem-worklog-tasks-description (cons (vector name key nil) xwem-worklog-tasks-description))))
    ))

(defun xwem-worklog-find-task (name &optional create)
  "Search for task with NAME in tasks list."
  (let ((tasks xwem-worklog-task-list))
    (while (and tasks (not (string= name (xwem-worklog-task-name (car tasks)))))
      (setq tasks (cdr tasks)))

    (if (or tasks (not create))
        (car tasks)

      (let ((task (make-xwem-worklog-task :name name)))
        (setq xwem-worklog-task-list (cons task xwem-worklog-task-list))
        task))))

(defun xwem-worklog-lookup-description (name)
  "Lookup description for task named by NAME."
  (let ((tal xwem-worklog-tasks-description))
    (while (and tal (not (string= (aref (car tal) 0) name)))
      (setq tal (cdr tal)))
    (car tal)))

(define-xwem-command xwem-worklog-begin-task (name &optional arg)
  "Start new worklog task named after NAME.
If prefix ARG is specified, and we are in pause, than resume."
  (xwem-interactive (list (xwem-completing-read "Task name: "
                                                (mapcar (lambda (el)
                                                          (list (aref el 0)))
                                                        xwem-worklog-tasks-description))
                          xwem-prefix-arg))

  (when xwem-worklog-current-task
    ;; Some task runned
    (xwem-worklog-end-task xwem-worklog-current-task))

  ;; Register in `xwem-worklog-tasks-description'
  (when (and (xwem-interactive-p)
             xwem-worklog-register-new-tasks)
    (xwem-worklog-register-task name))

  ;; go go go!
  (setq xwem-worklog-current-task
        (xwem-worklog-find-task name t))
  
  (unless (and xwem-worklog-pause-p
               (not (or xwem-worklog-pause-dont-stop
                        (xwem-worklog-pause-prefix-arg xwem-worklog-pause-p))))
    (xwem-worklog-resume-task xwem-worklog-current-task))

  (when (and (or arg xwem-worklog-auto-continue)
             xwem-worklog-pause-p)
    (xwem-worklog-pause-stop)
    (xwem-worklog-resume-task xwem-worklog-current-task))
    
  (run-hooks 'xwem-worklog-task-start-hook)

  (xwem-message 'info "WORKLOG: new task '%s' started." name))

(define-xwem-command xwem-worklog-end-task (task &optional arg)
  "Stop TASK.
By default `xwem-worklog-current-task' assumed.
If prefix ARG is specified, and we are in pause, than resume."
  (xwem-interactive (list xwem-worklog-current-task xwem-prefix-arg))

  (when (or arg xwem-worklog-auto-continue)
    (xwem-worklog-pause-stop))

  (when task
    (xwem-worklog-pause-task task)
    (xwem-worklog-task-update-total-time task)
    (xwem-worklog-task-update-today-time task)

    (xwem-message 'info "WORKLOG: task '%s' stoped." (xwem-worklog-task-name xwem-worklog-current-task))
    (setq xwem-worklog-current-task nil))
  )

(defun xwem-worklog-task-change-time (how arg)
  "Change runtime of current task by ARG minutes.
HOW is one of '- or '+."
  (when (and xwem-worklog-current-task
             (caar (xwem-worklog-task-times xwem-worklog-current-task)))
    (let ((ctime (decode-time (caar (xwem-worklog-task-times xwem-worklog-current-task)))))
      (setcar (cdr ctime)
              (funcall how (cadr ctime) arg))
      (setcar (car (xwem-worklog-task-times xwem-worklog-current-task))
              (apply 'encode-time ctime)))))

(define-xwem-command xwem-worklog-task-time-increase (arg)
  "Increase runtime of current task by ARG minutes."
  (xwem-interactive "p")

  (xwem-worklog-task-change-time '- arg))

(define-xwem-command xwem-worklog-task-time-decrease (arg)
  "Decrease runtime of current task by ARG minutes."
  (xwem-interactive "p")

  (xwem-worklog-task-change-time '+ arg))

(defun xwem-worklog-pause-task (task)
  "Pause task named by NAME."
  (unless (cdr (car (xwem-worklog-task-times task)))
    (setcdr (car (xwem-worklog-task-times task))
            (current-time))

    (when xwem-worklog-auto-worklog-file
      ;; XXX logout/login is special tasks that does not need to be
      ;; stoped
      (unless (or (string= (xwem-worklog-task-name task) "logout")
                  (string= (xwem-worklog-task-name task) "login"))
        (xwem-worklog-add-entry "stop")))
  ))

(defun xwem-worklog-resume-task (task)
  "Resume TASK."
  (when (or (null (xwem-worklog-task-times task))
            (cdr (car (xwem-worklog-task-times task))))
    (setf (xwem-worklog-task-times task)
          (cons (cons (current-time) nil) (xwem-worklog-task-times task)))
    (when xwem-worklog-auto-worklog-file
      (xwem-worklog-add-entry (xwem-worklog-task-name task)))
    ))

(defun xwem-worklog-task-update-total-time (task)
  "Update total-time entry of TASK."
  (setf (xwem-worklog-task-total-time task)
        (apply 'xwem-worklog-calc-time
               (mapcar (lambda (el)
                         (xwem-worklog-time-diff (cdr el) (car el)))
                       (xwem-worklog-task-times task)))))

(defun xwem-worklog-task-update-today-time (task)
  "Update today-time entry of TASK."
  (let ((ttimes (xwem-worklog-task-times task))
        (ctime (decode-time (current-time)))
        stime etime rttimes)
    ;; Set secs, mins, hours to 0
    (setcar ctime 0)
    (setcar (cdr ctime) 0)
    (setcar (cddr ctime) 0)
    (setq stime (apply 'encode-time ctime))

    ;; Set secs=59, mins=59, hours=23
    (setcar ctime 59)
    (setcar (cdr ctime) 59)
    (setcar (cddr ctime) 23)
    (setq etime (apply 'encode-time ctime))

    (while ttimes
      (setq ctime (car ttimes))
      (if (and (car ctime) (cdr ctime)
               (xwem-worklog-time-> (car ctime) stime)
               (xwem-worklog-time-< (cdr ctime) etime))
          (setq rttimes (cons ctime rttimes)))
      (setq ttimes (cdr ttimes)))

    (setf (xwem-worklog-task-today-time task)
          (and rttimes
               (apply 'xwem-worklog-calc-time
                      (mapcar (lambda (el)
                                (xwem-worklog-time-diff (cdr el) (car el)))
                              rttimes))))))

(defun xwem-worklog-calc-time (ct &rest diffs)
  "Calculate total time."
  (if (or (null diffs) (null (car diffs)))
      ct

    (let ((a (+ (nth 0 ct) (nth 0 (car diffs))))
          (b (+ (nth 1 ct) (nth 1 (car diffs)))))
      (when (> b 65535)
        (setq a (1+ a))
        (setq b (- b 65536)))

      (apply 'xwem-worklog-calc-time (cons (list a b) (cdr diffs))))))

(defun xwem-worklog-post-command ()
  "Function used in `xwem-post-command-hook'."
  (when xwem-worklog-pause-p
    (xwem-worklog-pause-update t))

  (when (eq (xwem-kbd-current-map) xwem-worklog-pause-map)
    (setq xwem-this-command-keys []))
  )

(define-xwem-command xwem-worklog-pause (arg &optional type)
  "Pause task counting.
If called with prefix ARG, than do not pause current task, if any."
  (xwem-interactive "P")

  (xwem-message 'info "worklog %S" type)

  ;; Since we will block here, we need to reset `xwem-prefix-arg'
  (setq xwem-prefix-arg nil)

  (if xwem-worklog-pause-p
      ;; Already paused .. so just change type
      (progn
        (setf (xwem-worklog-pause-prefix-arg xwem-worklog-pause-p) arg)
        (setf (xwem-worklog-pause-type xwem-worklog-pause-p) (or type 'pause)))

    ;; Pause current task, if we are not already in pause
    (when (and xwem-worklog-current-task
               (not (or arg xwem-worklog-pause-dont-stop)))
      (xwem-worklog-pause-task xwem-worklog-current-task)
      (xwem-worklog-task-update-total-time xwem-worklog-current-task)
      (xwem-worklog-task-update-today-time xwem-worklog-current-task))

    (xwem-worklog-pause-start (or type 'pause) arg)
    (let ((xwem-override-map xwem-worklog-pause-map)
          xev)
      (xwem-kbd-stop-grabbing)
      (xwem-kbd-start-grabbing xwem-worklog-pause-cursor)
      (setq xwem-this-command-keys [])

      (unwind-protect
          (while xwem-worklog-pause-p
            (setq xev (xwem-next-event 1))
            (if (not xev)
                ;; Timeout
                (xwem-worklog-pause-update)

              ;; Event arrived
              (X-Event-CASE xev
                (:X-KeyPress
                 (unless (xwem-kbd-kcode-modifier-p (X-Event-xkey-keycode xev))
                   (xwem-kbd-handle-keybutton xev)

                   ;; XXX
                   (if (eq (xwem-kbd-current-map) xwem-worklog-pause-map)
                       (setq xwem-this-command-keys [])
                     (setq xwem-override-map xwem-worklog-pause-map))

                   (when xwem-worklog-pause-p
                     (xwem-worklog-pause-update t))))

                ((:X-ButtonPress :X-ButtonRelease)
                 (xwem-kbd-handle-keybutton xev)
                 (when xwem-worklog-pause-p
                   (xwem-worklog-pause-update t)))
              )))

        ;; Ungrab keyboard and stop pauser if any
        (xwem-worklog-pause-stop)
        (xwem-kbd-stop-grabbing))
      )))

(define-xwem-command xwem-worklog-task-list (arg)
  "Display task list using pause window."
  (xwem-interactive "P")

  (let ((xwem-worklog-pause-window-update-hook
         (when xwem-worklog-use-diagram
           (list 'xwem-worklog-show-color-breaks 'xwem-worklog-draw-today-diagram))))
    (xwem-worklog-pause arg 'list)))

(define-xwem-command xwem-worklog-continue (arg)
  "Continue run current task."
  (xwem-interactive "P")

  (xwem-worklog-pause-stop)

  (when xwem-worklog-current-task
    (xwem-worklog-resume-task xwem-worklog-current-task)
    (xwem-message 'info "WORKLOG: continuing '%s' task" (xwem-worklog-task-name xwem-worklog-current-task)))
  )

(defun xwem-worklog-pause-start (type arg)
  "Start xwem worklog pausing."
  (if xwem-worklog-pause-p
      ;; Already exists, so just change type
      (setf (xwem-worklog-pause-type xwem-worklog-pause-p) type)

    ;; Create new pause window
    (setq xwem-worklog-pause-p
          (make-xwem-worklog-pause :type type
                                   :prefix-arg arg
                                   :pwin (xwem-worklog-pause-create-xwin)
                                   :pbuf (get-buffer-create " *worklog-pause*")
                                   :start-time (current-time)))
    
    ;; TODO: need to wait exposure event?
    (xwem-worklog-pause-update t)
    ))

(defun xwem-worklog-pause-stop ()
  "Stop xwem worklog pausing."

  (when xwem-worklog-pause-p
    (when (X-Win-p (xwem-worklog-pause-pwin xwem-worklog-pause-p))
      (XDestroyWindow (xwem-dpy) (xwem-worklog-pause-pwin xwem-worklog-pause-p)))
    (when (bufferp (xwem-worklog-pause-pbuf xwem-worklog-pause-p))
      (kill-buffer (xwem-worklog-pause-pbuf xwem-worklog-pause-p)))

    (setq xwem-worklog-pause-p nil)))
                           
(defun xwem-worklog-pause-create-xwin ()
  "Create pause window in center of selected frame.."
  ;; Create cursor
  (unless xwem-worklog-pause-cursor
    (setq xwem-worklog-pause-cursor
          (xwem-make-cursor (eval xwem-worklog-pause-cursor-shape)
                            xwem-worklog-pause-cursor-foreground-color
                            xwem-worklog-pause-cursor-background-color)))

  (let* ((xfgeom (xwem-frame-xgeom (xwem-frame-selected)))
         (xwin (XCreateWindow (xwem-dpy) nil
                              (+ (X-Geom-x xfgeom) (/ (- (X-Geom-width xfgeom) xwem-worklog-pwin-width) 2))
                              (+ (X-Geom-y xfgeom) (/ (- (X-Geom-height xfgeom) xwem-worklog-pwin-height) 2))
                              xwem-worklog-pwin-width xwem-worklog-pwin-height xwem-worklog-pwin-border-width nil nil nil
                              (make-X-Attr :override-redirect t
                                           :background-pixel (XAllocNamedColor (xwem-dpy) (XDefaultColormap (xwem-dpy))
                                                                               xwem-worklog-pwin-background)
                                           :border-pixel (XAllocNamedColor (xwem-dpy) (XDefaultColormap (xwem-dpy))
                                                                           xwem-worklog-pwin-border-color)
                                           :event-mask (Xmask-or XM-Exposure
                                                                 XM-StructureNotify
                                                                 XM-ButtonPress XM-ButtonRelease)))))
    (XMapWindow (xwem-dpy) xwin)
    (XRaiseWindow (xwem-dpy) xwin)
    xwin))

(defun xwem-worklog-time-diff (a b)
  "Return the difference between two times.
This function requires the second argument B to be earlier in time
than the first argument A."
  (cond ((= (nth 0 a) (nth 0 b)) (list 0 (- (nth 1 a) (nth 1  b))))
        ((> (nth 1 b) (nth 1 a)) (list (- (nth 0 a) (nth 0 b) 1)
                                       (- (+ 65536 (nth 1 a)) (nth 1 b))))
        (t (list (- (nth 0 a) (nth 0 b))
                 (- (nth 1 a) (nth 1 b))))))

(defun xwem-worklog-time-sum (&optional a &rest b)
  "Return the sum of two times A and B."
  (unless a
    (setq a '(0 0)))

  (if (or (not b) (not (car b)))
      a

    (let* ((rt1 (+ (nth 0 a) (nth 0 (car b))))
           (rt2 (+ (nth 1 a) (nth 1 (car b)))))
      (when (> rt2 65535)
        (setq rt2 (% rt2 65536))
        (setq rt1 (1+ rt1)))
      (apply 'xwem-worklog-time-sum (cons (list rt1 rt2) (cdr b)))
      )))

(defun xwem-worklog-format-time (time &optional padlen)
  "Return string."
  (let (rawtime days hours minutes seconds lfm)
    ;; XXX can't deal with car
    (if (not (zerop (car time)))
        (setq rawtime (+ (* 65536.0 (car time)) (cadr time)))
      (setq rawtime (float (cadr time))))

    (setq days (truncate (/ rawtime (* 60 60 24))))
    (setq rawtime (- rawtime (* 60 60 24 days)))
    (setq hours (truncate (/ rawtime (* 60 60))))
    (setq rawtime (- rawtime (* 60 60 hours)))
    (setq minutes (truncate (/ rawtime 60)))
    (setq rawtime (- rawtime (* 60 minutes)))
    (setq seconds (truncate rawtime))

    (setq lfm
          (cond ((not (zerop days)) (format "%dd %dh" days hours))
                ((not (zerop hours)) (format "%dh %dm" hours minutes))
                (t (format "%dm %ds" minutes seconds))))
    (if padlen
        (if (> padlen (length lfm))
            (concat lfm (make-string (- padlen (length lfm)) ?\x20))
          (substring lfm 0 padlen))
      lfm)))

(defun xwem-worklog-pause-update (&optional full)
  "Redraw pause win."
  (with-current-buffer (xwem-worklog-pause-pbuf xwem-worklog-pause-p)
    (erase-buffer)

    (insert "XWEM Worklog mode ")
    (insert-face "PAUSE: " 'red)
    (insert (xwem-worklog-format-time
             (xwem-worklog-time-diff (current-time)
                                     (xwem-worklog-pause-start-time xwem-worklog-pause-p))
             20))
    (insert "\n\n")

    (if (eq (xwem-worklog-pause-type xwem-worklog-pause-p) 'pause)
        (xwem-worklog-insert-current-task)
      (xwem-worklog-insert-task-list))

    (insert "\n")
    (insert "Press any key to continue with current task.\n")
    (if (eq (xwem-worklog-pause-type xwem-worklog-pause-p) 'list)
        (insert (substitute-command-keys "Press ``\\<xwem-worklog-pause-map>\\[xwem-worklog-pause]'' to show pause buffer.\n"))

      (insert "Bindings:\n")
      (insert "Key             Binding\n")
      (insert "---             -------\n")
      (describe-bindings-internal xwem-worklog-pause-map))

    (X-Dpy-send-excursion (xwem-dpy)
      (when full
        (XClearArea (xwem-dpy) (xwem-worklog-pause-pwin xwem-worklog-pause-p)
                    0 0 xwem-worklog-pwin-width xwem-worklog-pwin-height nil))
      (xwem-misc-textsp-show (xwem-worklog-pause-pwin xwem-worklog-pause-p)
                             20 20       ; XXX
                             (xwem-misc-buffer->textsp 'default))

      (when full
        ;; XXX 
        (run-hooks 'xwem-worklog-pause-window-update-hook))
    )))

(defun xwem-worklog-last-time-string (task &optional padlen)
  "Return time string of last time of TASK was runned."
  (let ((ctime (or (cdr (car (xwem-worklog-task-times task))) (current-time))))
    (if (caar (xwem-worklog-task-times xwem-worklog-current-task))
        (xwem-worklog-format-time
         (xwem-worklog-time-diff ctime
                                 (caar (xwem-worklog-task-times xwem-worklog-current-task)))
         padlen)

      (if padlen
          (concat "---" (make-string (- padlen 3) ?\x20)) ; XXX
        "---"))))
    
(defun xwem-worklog-get-today-time (task)
  "Return time TASK was runned today."
  (if (cdr (car (xwem-worklog-task-times task)))
      (or (xwem-worklog-task-today-time task) '(0 0))

    ;; Task not paused
    (if (caar (xwem-worklog-task-times task))
         (xwem-worklog-calc-time
          (xwem-worklog-time-diff (current-time) (caar (xwem-worklog-task-times task)))
          (xwem-worklog-task-today-time task))
      '(0 0))))

(defun xwem-worklog-get-total-time (task)
  "Return total time TASK was runned."
  (if (cdr (car (xwem-worklog-task-times task)))
      (or (xwem-worklog-task-total-time task) '(0 0))
  
    ;; Task not paused
    (if (caar (xwem-worklog-task-times task))
         (xwem-worklog-calc-time
          (xwem-worklog-time-diff (current-time) (caar (xwem-worklog-task-times task)))
          (xwem-worklog-task-total-time task))
      '(0 0))))
  
(defun xwem-worklog-today-time-string (task &optional padlen)
  "Return time string for today time of TASK."
  (if (cdr (car (xwem-worklog-task-times task)))
      (if (xwem-worklog-task-today-time task)
          (xwem-worklog-format-time (xwem-worklog-task-today-time task) padlen)

        (if padlen
            (concat "---" (make-string (- padlen 3) ?\x20)) ; XXX
          "---"))

    ;; Task not paused
    (if (caar (xwem-worklog-task-times task))
        (xwem-worklog-format-time
         (xwem-worklog-calc-time
          (xwem-worklog-time-diff (current-time) (caar (xwem-worklog-task-times task)))
          (xwem-worklog-task-today-time task))
         padlen)
      
      (if padlen
          (concat "---" (make-string (- padlen 3) ?\x20)) ; XXX
        "---"))))

(defun xwem-worklog-total-time-string (task &optional padlen)
  "Return time string for total time of TASK."
  (if (cdr (car (xwem-worklog-task-times task)))
      (if (xwem-worklog-task-total-time task)
          (xwem-worklog-format-time (xwem-worklog-task-total-time task) padlen)

        (if padlen
            (concat "---" (make-string (- padlen 3) ?\x20)) ; XXX
          "---"))

    ;; Task not paused
    (if (caar (xwem-worklog-task-times task))
        (xwem-worklog-format-time
         (xwem-worklog-calc-time
          (xwem-worklog-time-diff (current-time) (caar (xwem-worklog-task-times task)))
          (xwem-worklog-task-total-time task))
         padlen)

      (if padlen
          (concat "---" (make-string (- padlen 3) ?\x20)) ; XXX
        "---"))))
  
(defun xwem-worklog-insert-task-list ()
  "Insert into pause buffer list of registered tasks and their values."
  (let* ((noff 10)
         (mlen (or (and xwem-worklog-task-list
                        (+ (apply 'max (mapcar (lambda (el)
                                                 (length (xwem-worklog-task-name el)))
                                               xwem-worklog-task-list))
                           noff))
                   20))
         (task-hdr "Task"))
    (insert task-hdr)
    (insert (make-string (- mlen (length task-hdr)) ?\x20))
    (insert "Today Time    Total time\n")
    (insert (make-string (length task-hdr) ?-))
    (insert (make-string (- mlen (length task-hdr)) ?\x20))
    (insert "----- ----    ----- ----\n")

    (mapc (lambda (task)
            (if (eq task xwem-worklog-current-task)
                (insert-face (xwem-worklog-task-name task) 'bold)
              (insert (xwem-worklog-task-name task)))

            (move-to-column mlen t)

            ;; Insert today time
            (insert (xwem-worklog-today-time-string task 14))
                         
            ;; Insert total time
            (insert (xwem-worklog-total-time-string task 10))

            (insert "\n"))
          xwem-worklog-task-list)

    ;; Insert grand total
    (let ((tl (copy-list xwem-worklog-task-list)))
      ;; Remove 'login', 'logout' tasks from task list
      (setq tl (delete* nil tl :test (lambda (e1 e2)
                                       (or (string= "login" (xwem-worklog-task-name e2))
                                           (string= "logout" (xwem-worklog-task-name e2))))))

      (insert (concat (make-string (+ 14 10 mlen) ?-) "\n"))
      (insert "Grand Total:")
      (move-to-column mlen t)
      (insert (xwem-worklog-format-time
               (apply 'xwem-worklog-time-sum
                      (mapcar 'xwem-worklog-get-today-time tl)) 14))
      (insert (xwem-worklog-format-time
               (apply 'xwem-worklog-time-sum
                      (mapcar 'xwem-worklog-get-total-time tl)) 10))

      (insert "\n"))
    ))

(defun xwem-worklog-insert-current-task ()
  "Insert state of current task into pause buffer."
  (if (not xwem-worklog-current-task)
      (insert "  No active task.\n")

    ;; Got active task
    (insert "  Current task: ")
    (insert-face (xwem-worklog-task-name xwem-worklog-current-task) 'bold)
    (insert "\n")

    (unless (cdr (car (xwem-worklog-task-times xwem-worklog-current-task)))
      ;; Task not paused
      (insert (format "  Task time:    %s\n"
                      (xwem-worklog-last-time-string xwem-worklog-current-task 20)))
      (insert (format "  Today time:   %s\n"
                      (xwem-worklog-today-time-string xwem-worklog-current-task 20)))
      (insert (format "  Total time:   %s\n"
                      (xwem-worklog-total-time-string xwem-worklog-current-task 20)))
      )))

(defun xwem-worklog-time-> (a-time b-time)
  "Return non-nil if A-TIME is >= than B-TIME."
  (or (> (nth 0 a-time) (nth 0 b-time))
      (and (= (nth 0 a-time) (nth 0 b-time))
           (>= (nth 1 a-time) (nth 1 b-time)))))

(defun xwem-worklog-time-< (a-time b-time)
  "Return non-nil if A-TIME is <= than B-TIME."
  (or (< (nth 0 a-time) (nth 0 b-time))
      (and (= (nth 0 a-time) (nth 0 b-time))
           (<= (nth 1 a-time) (nth 1 b-time)))))

(defun xwem-worklog-add-entry (string &optional time)
  "Add entry to `xwem-worklog-file'."
  (require 'worklog)

  (let ((buf (find-file-noselect (expand-file-name xwem-worklog-file xwem-dir))))
    (save-excursion
      (unwind-protect
          (with-current-buffer buf
            ;; Avoid using `end-of-buffer'
            (goto-char (point-max))
            (unless (bolp)
              (newline))
            (insert (worklog-make-date-time) " ")

            (insert (concat string "\n"))
            (save-buffer))
        (kill-buffer buf)))))

(defun xwem-worklog-show ()
  "Show xwem worklog file."
  (interactive)
  
  (require 'worklog)
  (find-file (expand-file-name xwem-worklog-file xwem-dir))
  (worklog-mode))

(defun xwem-worklog-summarize ()
  "Just like `worklog-summarize-tasks', but uses xwem worklog file."
  (interactive)
  (require 'worklog)

  (let ((worklog-file (expand-file-name xwem-worklog-file xwem-dir)))
    (worklog-summarize-tasks)))

(defun xwem-worklog-write-file (&optional file)
  "Write FILE in `worklog.el' format.
If FILE is not given, `xwem-worklog-file' from `xwem-dir' will be used."
  (require 'worklog)

  (let ((buf (find-file-noselect (or file (expand-file-name xwem-worklog-file xwem-dir)))))
    (unwind-protect
        (with-current-buffer buf
          (goto-char (point-max))       ; append to the end of buffer

          ;; TODO:
          ;;   - write me
          (save-buffer))
      (kill-buffer buf))))

(defun xwem-worklog-read-file (&optional time)
  "Read FILE in `worklog.el' format.
If FILE is not given, `xwem-worklog-file' from `xwem-dir' will be used."
  (require 'worklog)

  (let ((buf (find-file-noselect (expand-file-name xwem-worklog-file xwem-dir))))
    (unwind-protect
        (with-current-buffer buf
          (goto-char (point-min))

          ;; TODO:
          ;;   - write me
          )
      (kill-buffer buf))))

;; Worklog notification facilities
(defvar xwem-worklog-notifier-timer nil
  "itimer used to notify you.
Internal variable, DO NOT MODIFY.")

(defvar xwem-worklog-auto-timer nil
  "itimer used to autologout or to stop login notifier.
Internal variable, DO NOT MODIFY.")

(defun xwem-worklog-notifier-stop ()
  "Login notifier stopper."
  (when (itimerp xwem-worklog-auto-timer)
    (delete-itimer xwem-worklog-auto-timer)
    (setq xwem-worklog-auto-timer nil))

  (when (itimerp xwem-worklog-notifier-timer)
    (delete-itimer xwem-worklog-notifier-timer)
    (setq xwem-worklog-notifier-timer nil)))
  
(define-xwem-command xwem-worklog-login ()
  "Stop login notifier, start logout notifier."
  (xwem-interactive)

  (xwem-worklog-notifier-stop)
    
  ;; Install logout notifier
  (setq xwem-worklog-notifier-timer
        (xwem-worklog-today-start-at xwem-worklog-day-ends 0
                                     'xwem-worklog-logout-notifier
                                     (* 60 xwem-worklog-logout-notify-period)))

  ;; Recalculate today time for every task
  (mapc (lambda (task)
          (xwem-worklog-task-update-today-time task))
        xwem-worklog-task-list)
          
  (xwem-worklog-begin-task "login")
  (run-hooks 'xwem-worklog-login-hook))

(define-xwem-command xwem-worklog-logout ()
  "Stop logout notifier, start login notifier."
  (xwem-interactive)

  (xwem-worklog-notifier-stop)

  ;; Install login notifier
  (setq xwem-worklog-notifier-timer
        (xwem-worklog-tomorow-start-at xwem-worklog-day-start 0
                                       'xwem-worklog-login-notifier
                                       (* 60 xwem-worklog-login-notify-period)))

  (xwem-worklog-begin-task "logout")
  (run-hooks 'xwem-worklog-logout-hook))
    
(defun xwem-worklog-login-notifier ()
  "Notify that you must login."
  (unless (itimerp xwem-worklog-auto-timer)
    ;; Start login notify stopper
    (setq xwem-worklog-auto-timer
          (start-itimer "xwem-worklog-login-notify-stopper"
                        'xwem-worklog-notifier-stop
                        (* 60 xwem-worklog-login-stop-period))))

  (xwem-message 'asis (concat (xwem-str-with-faces "XWEM WORKLOG: " '(red bold))
                              "Workday started, but you're not logged in."))
  (xwem-play-sound 'alarm))

(defun xwem-worklog-logout-notifier ()
  "Notify that you need to logout."
  (unless (itimerp xwem-worklog-auto-timer)
    ;; Start autologouter
    (setq xwem-worklog-auto-timer
          (start-itimer "xwem-worklog-autologout"
                        'xwem-worklog-logout
                        (* 60 xwem-worklog-logout-auto-period))))

  (xwem-message 'asis (concat (xwem-str-with-faces "XWEM WORKLOG: " '(red bold))
                              "Workday ended, but you're still working."))
  (xwem-play-sound 'alarm))

(defun xwem-worklog-doat (time func &optional restart)
  "Run function FUNC at a given TIME.
Return itimer handler."
  (let ((ctime (current-time))
        rtime)
    (when (xwem-worklog-time-> time ctime)
      (setq rtime (xwem-worklog-time-diff time ctime))
      (setq rtime (+ (* (float (car rtime)) 65536)
                     (cadr rtime)))

      (start-itimer "doat" func rtime restart))
    ))

(defun xwem-worklog-tomorow-start-at (hour min fun &optional restart)
  "Run function FUN tomorow at HOUR and MIN."
  (let ((ctime (decode-time (current-time))))
    (setcar ctime 0)
    (setcar (cdr ctime) min)
    (setcar (cddr ctime) hour)
    (setcar (cdddr ctime) (1+ (nth 3 ctime)))

    (xwem-worklog-doat (apply 'encode-time ctime) fun restart)))

(defun xwem-worklog-today-start-at (hour min fun &optional restart)
  "Run function FUN today at HOUR and MIN."
  (let ((ctime (decode-time (current-time))))
    (setcar ctime 0)
    (setcar (cdr ctime) min)
    (setcar (cddr ctime) hour)

    (xwem-worklog-doat (apply 'encode-time ctime) fun restart)))

;; Diagram drawing
(defun xwem-worklog-show-color-breaks ()
  "Show color breaks."

  (when (eq (xwem-worklog-pause-type xwem-worklog-pause-p) 'list)
    ;; Do it only in listing
    (let* ((tmp-face (make-face 'tmp-face))
           (face-height (font-height (face-font 'default)))
           (w 10)
           (y (- (* 5 face-height) (/ w 2)))
           (x 6))
      (mapc (lambda (task)
              (let ((d (xwem-worklog-lookup-description (xwem-worklog-task-name task))))
                (xwem-face-set-foreground tmp-face (or (and d (aref d 2)) "black"))
                (xwem-diag-draw-rect (xwem-worklog-pause-pwin xwem-worklog-pause-p)
                                     (xwem-face-get-gc 'default)
                                     (cons x y) (cons (+ x w) y)
                                     (cons (+ x w) (+ y w)) (cons x (+ y w)) (xwem-face-get-gc tmp-face))
                (setq y (+ y face-height))))
            xwem-worklog-task-list)
      )))

(defun xwem-worklog-generate-percentage-spec (sector-width &optional no-labels no-yoff)
  "Generates percentage diagram spec.
If NO-LABELS is non-nil, labels will be avoided."
  (let ((today-seconds (* 60.0 60 (- xwem-worklog-day-ends xwem-worklog-day-start)))
        spec spec1)

    (setq spec1 (mapcar (lambda (task)
                          (let* ((d (xwem-worklog-lookup-description (xwem-worklog-task-name task)))
                                 (tt (xwem-worklog-get-today-time task))
                                 (ts (+ (* (car tt) 65536.0) (cadr tt)))
                                 (per (truncate (* 100.0 (/ ts today-seconds))))
                                 (rv (and d (> per 0)
                                          (vector per (not no-labels) (aref d 2) 0 0
                                                  (if (and (not no-yoff) (eq task xwem-worklog-current-task))
                                                      (- (/ sector-width 2)) 0)))))
                            rv))
                        xwem-worklog-task-list))

    ;; Remove invalid fields
    (while spec1
      (when (car spec1)
        (setq spec (cons (car spec1) spec)))
      (setq spec1 (cdr spec1)))

    spec))
  
(defun xwem-worklog-draw-today-diagram ()
  ""
  (when (eq (xwem-worklog-pause-type xwem-worklog-pause-p) 'list)
    ;; Do it only in listing
    (let* ((buf-lines (with-current-buffer (xwem-worklog-pause-pbuf xwem-worklog-pause-p) (count-lines (point-min) (point-max))))
           (face-height (font-height (face-font 'default)))
           (t-off 2)
           (y-off (* face-height (+ t-off buf-lines)))
           (x-off 50)
           (sec-hei 20)
           (wwid (- xwem-worklog-pwin-width (* x-off 2)))
           (whei (- xwem-worklog-pwin-height y-off (* face-height 2 t-off) sec-hei))
           (spec (xwem-worklog-generate-percentage-spec sec-hei)))

      ;; XXX
      (when spec
        (xwem-diag-draw-percentage
         xwem-worklog-diagram-type spec (xwem-worklog-pause-pwin xwem-worklog-pause-p)
         (xwem-face-get-gc 'default) x-off y-off wwid whei sec-hei))
      )))

;;; Worklog dockapp
(defconst xwem-worklog-dockapp-event-mask
  (list XM-Exposure XM-StructureNotify XM-ButtonPress XM-ButtonRelease))

(defun xwem-worklog-meaning-update-time ()
  "Return seconds."
  (/ (* 60 60 (- xwem-worklog-day-ends xwem-worklog-day-start)) 100))

(defun xwem-worklog-dockapp-event-handler (xdpy xwin xev)
  "Event handler for worklog dockapp."
  (X-Event-CASE xev
    (:X-Expose
     (xwem-worklog-dockapp-update))

    (:X-DestroyNotify
     (delete-itimer (xwem-worklog-dockapp-update-itimer xwem-worklog-dockapp))
     (remove-hook 'xwem-worklog-task-start-hook 'xwem-worklog-dockapp-update)
     (setq xwem-worklog-dockapp nil))
    ))

(defun xwem-worklog-dockapp-update ()
  "Update worklog dockapp."
  (when xwem-worklog-dockapp
    (let* ((win (xwem-worklog-dockapp-win xwem-worklog-dockapp))
           (xdpy (X-Win-dpy win))
           (w (xwem-worklog-dockapp-width xwem-worklog-dockapp))
           (h (xwem-worklog-dockapp-height xwem-worklog-dockapp))
           (sec-w (xwem-worklog-dockapp-sector-width xwem-worklog-dockapp))
           (spec (xwem-worklog-generate-percentage-spec sec-w t t)))

        (X-Dpy-send-excursion xdpy
          (XClearArea xdpy win 0 0 (+ 1 w) (+ 1 h (* 2 sec-w)) nil)
          (when spec
            (xwem-diag-draw-percentage
             xwem-worklog-dockapp-diagram-type
             spec win (xwem-face-get-gc 'default)
             (/ sec-w 2) (/ sec-w 2) w h sec-w))

          (when xwem-worklog-current-task
            (let ((rd (xwem-worklog-lookup-description (xwem-worklog-task-name xwem-worklog-current-task)))
                  tface)
              (when rd
                 (setq tface (make-face 'temp-face))
                 (xwem-face-set-foreground tface (or (aref rd 2) "black"))
                 (XFillRectangle xdpy win (xwem-face-get-gc tface) 0 0 6 6))
              ))
          ))
    ))

;;;###autoload
(defun xwem-worklog-start-dockapp (&optional xdpy w h sector-width)
  "Start dockapp."
  (unless xdpy
    (setq xdpy (xwem-dpy)))
  (unless w
    (setq w 32))                        ; XXX
  (unless h
    (setq h 24))                        ; XXX
  (unless sector-width
    (setq sector-width 0))              ; XXX

  (let ((wd (make-xwem-worklog-dockapp
             :win (XCreateWindow xdpy nil 0 0 (+ 1 w) (+ 1 h (* 2 sector-width)) 0 nil nil nil
                                 (make-X-Attr :override-redirect t
                                              :background-pixel (XAllocNamedColor xdpy (XDefaultColormap xdpy)
                                                                                  (face-background-name 'default)) ; XXX
                                              ))
             :width w :height h :sector-width sector-width)))

    (setq xwem-worklog-dockapp wd)

    (XSelectInput xdpy (xwem-worklog-dockapp-win wd) (apply 'Xmask-or xwem-worklog-dockapp-event-mask))
    (X-Win-EventHandler-add (xwem-worklog-dockapp-win wd) 'xwem-worklog-dockapp-event-handler nil
			    (list X-Expose X-ButtonPress X-ButtonRelease
				  X-DestroyNotify))

    ;; Initialize wd in sys tray
    (XTrayInit xdpy (xwem-worklog-dockapp-win wd))

    ;; Start updater
    (setf (xwem-worklog-dockapp-update-itimer wd)
          (start-itimer "xwem-worklog-dockapp-updater" 'xwem-worklog-dockapp-update
                        (xwem-worklog-meaning-update-time) (xwem-worklog-meaning-update-time)))

    (add-hook 'xwem-worklog-task-start-hook 'xwem-worklog-dockapp-update)
    ))


(run-hooks 'xwem-worklog-load-hook)

(provide 'xwem-worklog)

;;; xwem-worklog.el ends here
