;;;_ Import
(use-modules (ice-9 popen)
             (ice-9 rdelim))

;;;_ Variables
(define modkey 'mod4)
(define dmenu-font
  "-misc-tamsyn-medium-r-normal-*-14-*-*-*-*-*-iso8859-*")
(define dmenu-cmd "dmenu")
(define dmenu-args
  (string-append
   "-b -nb '#000000' -nf '#15abc3' -sb '#e0c625' -sf '#000000' -fn '"
   dmenu-font "'"))
(define dzen-font
  "-misc-tamsyn-medium-r-normal-*-17-*-*-*-*-*-iso8859-*")
(define dzen-cmd "dzen2")
(define dzen-args
  (string-append " -fn '" dzen-font
                 "' -x 5 -y 5 -bg '#000000' -fg '#15abc3'"))
(define dzen-pipe '())

(define previous-tag '())
(define current-tag "default")
(define terminal "st")

;;;_ Macros
(define-macro (cmd command)
  `(lambda ()
     (run-command ,command)
     (reset-main-binding)))

(define-macro (create-map name binding . more)
  `(define (,name)
     (ungrab-all-keys)
     (remove-all-keys)
     (begin ,binding . ,more)
     (xbindkey-function `(,modkey g) reset-main-binding)
     (grab-all-keys)))

;;;_ Functions
(define (reset-main-binding)
  "reset first binding"
  (close-gui-window)
  (ungrab-all-keys)
  (remove-all-keys)
  (main-binding)
  (grab-all-keys))

(define (get-tags)
  "Get a list of tags"
  (let* ((file (open-input-pipe
                "TAGS=( $(herbstclient tag_status 0 | tr \":\\!.+#\" \" \") ); echo ${TAGS[@]}"))
         (tags (string-split (read-line file) #\ )))
    (close-port file)
    (set! tags (delete current-tag tags))
    (set! tags (delete previous-tag tags))
    (if (not (null? previous-tag))
        (append `(,previous-tag) (append tags `(,current-tag)))
        (append tags `(,current-tag)))))

(define (choose-tag prompt tags)
  "Ask to choose a tag"
  (let* ((file (open-input-pipe
                (string-append "echo '" (string-join tags "\n")
                               "' | " dmenu-cmd " " dmenu-args " -p '" prompt ":'")))
         (tag (read-line file)))
    (close-port file)
    tag))

(define (switch-to-tag tag)
  (let ((tags (get-tags)))
    (if (string? tag)
        (begin
          (if (not (member tag tags))
              (system (string-append "herbstclient add " tag)))
          (set! previous-tag current-tag)
          (set! current-tag tag)
          (run-command (string-append "herbstclient use " tag))))))

(define (switch-tags)
  "Switch to another tag"
  (let* ((tags (get-tags))
         (tag (choose-tag "Switch to tag" tags)))
    (switch-to-tag tag)
    (reset-main-binding)))

(define (switch-and-run)
  "Ask for a command to run, switch to a tag with that name and run
the command."
  (let* ((file (open-input-pipe
                (string-append "dmenu_pick -p 'Run:' " dmenu-args)))
         (prog (read-line file)))
    (close-port file)
    (if (string? prog)
        (begin
          (switch-to-tag prog)
          (run-command prog)))
  (reset-main-binding)))

(define (kill-tag)
  "Kill a selected tag"
  (let* ((tags (get-tags))
         (tag (choose-tag "Kill tag" tags)))
    (if (string? tag)
        (begin
          (if (member tag tags)
              (run-command (string-append "herbstclient merge_tag " tag)))))
    (reset-main-binding)))

(define (move-to-tag)
  "Move selected window to another tag"
  (let* ((tags (get-tags))
         (tag (choose-tag "Move to tag" tags)))
    (if (string? tag)
        (begin
          (if (not (member tag tags))
              (system (string-append "herbstclient add " tag)))
          (run-command (string-append "herbstclient move " tag))))
    (reset-main-binding)))

(define (text-width font text)
  (let* ((pipe (open-input-pipe (string-append "textwidth '" font "' '" text "'")))
         (width (read-line pipe)))
    (close-port pipe)
    (if (string? width)
        (string->number width)
        -1)))

(define (gui-print text)
  (close-gui-window)
  (let ((width (+ (text-width dzen-font text) 10)))
    (set! dzen-pipe (open-output-pipe
                     (string-append dzen-cmd " -w " (number->string width)
                                    " " dzen-args))))
  (display text dzen-pipe)
  (newline dzen-pipe))

(define (close-gui-window)
  (if (and (not (null? dzen-pipe))
           (not (port-closed? dzen-pipe)))
      (close-pipe dzen-pipe)
      (set! dzen-pipe '())))

;;;_ Maps
(define (main-binding)
  "First binding"
  (xbindkey `(,modkey shift "1") (string-append "dmenu_run -p 'Run:' " dmenu-args))
  (xbindkey `(,modkey "0") "herbstclient remove")
  (xbindkey `(,modkey "2") "herbstclient split vertical 0.5")
  (xbindkey `(,modkey "3") "herbstclient split horizontal 0.5")
  (xbindkey-function `(,modkey x) X-function-map)
  (xbindkey-function `(,modkey w) W-function-map)
  (xbindkey-function `(,modkey s) S-function-map)
  (xbindkey `(,modkey Return) terminal)
  (xbindkey '(control alt l) "i3lock -c 000000")
  (xbindkey '(XF86HomePage) "conkeror")
  (xbindkey '(XF86Mail) "mutt")
  (xbindkey '(XF86AudioPlay) "mpc toggle")
  (xbindkey '(XF86AudioStop) "mpc stop")
  (xbindkey '(XF86AudioMute) "amixer sset Master toggle")
  (xbindkey '(XF86AudioLowerVolume) "mcp volume -5")
  (xbindkey '(XF86AudioRaiseVolume) "mcp volume +5")
  (xbindkey '(XF86AudioPrev) "mpc prev")
  (xbindkey '(XF86AudioNext) "mpc next")
  (xbindkey '(XF86Tools) "ncmpcpp")
  (xbindkey `(,modkey b) "herbstclient focus left")
  (xbindkey `(,modkey n) "herbstclient focus down")
  (xbindkey `(,modkey p) "herbstclient focus up")
  (xbindkey `(,modkey f) "herbstclient focus right")
  (xbindkey-function `(,modkey g) reset-main-binding))

(create-map X-function-map
            (gui-print "S-x")
            (xbindkey-function '(b) switch-tags)
            (xbindkey-function `(,modkey c) (cmd "herbstclient quit"))
            (xbindkey-function `(,modkey r) (cmd "herbstclient reload"))
            (xbindkey-function '(k) kill-tag)
            (xbindkey-function '("0") (cmd "herbstclient remove"))
            (xbindkey-function '("3") (cmd "herbstclient split horizontal 0.5"))
            (xbindkey-function '("2") (cmd "herbstclient split vertical 0.5"))
            (xbindkey-function '(space) (cmd "herbstclient cycle_layout 1"))
            (xbindkey-function '(f) (cmd "herbstclient floating toggle"))
            (xbindkey-function '(shift f) (cmd "herbstclient fullscreen toggle"))
            (xbindkey-function '(p) (cmd "herbstclient pseudotile toggle"))
            (xbindkey-function '(r) resize-map)
            (xbindkey-function '(m) move-to-tag)
            (xbindkey-function `(,modkey f) switch-and-run))

(create-map W-function-map
            (gui-print "S-w")
            (xbindkey-function '(k) (cmd "herbstclient close"))
            (xbindkey-function '(w) (cmd "herbstclient cycle"))
            (xbindkey-function '(o) (cmd "herbstclient cycle_all +1"))
            (xbindkey-function '(b) (cmd "herbstclient focus left"))
            (xbindkey-function '(n) (cmd "herbstclient focus down"))
            (xbindkey-function '(p) (cmd "herbstclient focus up"))
            (xbindkey-function '(f) (cmd "herbstclient focus right"))
            (xbindkey-function '(shift b) (cmd "herbstclient shift left"))
            (xbindkey-function '(shift n) (cmd "herbstclient shift down"))
            (xbindkey-function '(shift p) (cmd "herbstclient shift up"))
            (xbindkey-function '(shift f) (cmd "herbstclient shift right")))

(create-map S-function-map
            (gui-print "S-s")
            (xbindkey-function '(o) (cmd "herbstclient cycle_monitor")))

(create-map resize-map
            (gui-print "Resizing")
            (xbindkey `(,modkey b) "herbstclient resize left +0.05")
            (xbindkey `(,modkey n) "herbstclient resize down +0.05")
            (xbindkey `(,modkey p) "herbstclient resize up +0.05")
            (xbindkey `(,modkey f) "herbstclient resize right +0.05")
            (xbindkey-function '(Return) reset-main-binding))

;;;_ Main
(main-binding)

;;;_ Local Variables
;; Local Variables:
;; eval: (git-auto-commit-mode 1)
;; End: