;;; jao-mpdn.el --- Notifications using elmpd    -*- lexical-binding: t; -*-

;; Copyright (C) 2021, 2022  jao

;; Author: jao <mail@jao.io>
;; Keywords: convenience
;; Version: 0.1
;; Package-requires: ((emacs "27.1") (elmpd "0.1.9"))
;; URL: https://codeberg.org/jao/lib/media

;; This program 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 of the License, or
;; (at your option) any later version.

;; This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; React to mpd player status changes.

;;; Code:

(require 'elmpd)
(require 'jao-minibuffer)

(defvar jao-mpdn--connection nil)
(defvar jao-mpdn-host "localhost")
(defvar jao-mpdn-port 6600)
(defvar-local jao-mpdn--local-port nil)

(defun jao-mpdn--disconnect (conn)
  (delete-process (elmpd-connection--fd conn)))

(defun jao-mpdn--connect (name &optional cb)
  (elmpd-connect :name name
                 :host jao-mpdn-host
                 :port jao-mpdn-port
                 :subsystems
                 (when cb `((player) . ,cb))))

(defun jao-mpdn-disconnect ()
  (interactive)
  (when jao-mpdn--connection
    (jao-mpdn--disconnect jao-mpdn--connection)
    (setq jao-mpdn--connection nil)))

(defun jao-mpdn-connect (&optional force)
  (interactive)
  (when force (jao-mpdn-disconnect))
  (unless jao-mpdn--connection
    (setq jao-mpdn--connection (jao-mpdn--connect "jao-mpc" 'jao-mpdn--watcher))
    (jao-mpdn--watcher jao-mpdn--connection 'player))
  jao-mpdn--connection)

(defun jao-mpdn--send (cmd cb)
  (elmpd-send jao-mpdn--connection cmd cb))

(defvar jao-mpdn--play-status '())
(defvar jao-mpdn--current '())
(defvar jao-mpdn-minibuffer-str "")

(defun jao-mpdn--parse-retort (txt)
  (let (res)
    (dolist (e (split-string txt "\n" t " ") res)
      (let ((e (split-string e ": " t " ")))
        (when (and (car e) (cadr e))
          (push (cons (car e) (cadr e)) res))))))

(defun jao-mpdn--update-status (next)
  (let ((cb (lambda (_c ok txt)
              (when ok
                (setq jao-mpdn--play-status (jao-mpdn--parse-retort txt))
                (when next (funcall next))))))
    (jao-mpdn--send "status" cb)))

(defun jao-mpdn--current-get (x &optional def)
  (alist-get x jao-mpdn--current def nil #'string=))

(defun jao-mpdn--status-get (x &optional def)
  (alist-get x jao-mpdn--play-status def nil #'string=))

(defun jao-mpdn--playing-p ()
  (string= (jao-mpdn--status-get "state" "") "play"))

(defun jao-mpdn--current-str ()
  (let ((title (jao-mpdn--current-get "Title"))
        (album (jao-mpdn--current-get "Album"))
        (no (string-to-number (jao-mpdn--current-get "Track" "0")))
        (len (string-to-number (jao-mpdn--status-get "playlistlength" "1")))
        (artist (jao-mpdn--current-get "Artist"))
        (composer (jao-mpdn--current-get "Composer")))
    (format " %s%s %s%s%s"
            (jao--put-face (if (zerop no) "" (format "%02d/%s " no len))
                           'jao-themes-f02)
            (jao--put-face title 'jao-themes-f00)
            (jao--put-face artist 'jao-themes-f01)
            (jao--put-face (if composer (format " [%s]" composer) "")
                           'jao-themes-f01)
            (jao--put-face (if album (format " (%s)" album) "") 'jao-themes-f11))))

(defun jao-mpdn--update-minibuffer ()
  (setq jao-mpdn-minibuffer-str
        (if (jao-mpdn--playing-p) (jao-mpdn--current-str) ""))
  (jao-minibuffer-refresh))

(defun jao-mpdn--update-current (&optional next)
  (let ((cb (lambda (_c ok txt)
              (when ok
                (setq jao-mpdn--current (jao-mpdn--parse-retort txt))
                (jao-mpdn--update-minibuffer)
                (cond (next (funcall next))
                      ((and (null jao-mpdn--current) jao-random-album-active)
                       (jao-random-album-next)))))))
    (jao-mpdn--send "currentsong" cb)))

(defun jao-mpdn--watcher (_conn _subsys)
  (jao-mpdn--update-status #'jao-mpdn--update-current))


;;;###autoload
(defun jao-mpdn-setup ()
  (jao-mpdn-connect t)
  (jao-minibuffer-add-msg-variable 'jao-mpdn-minibuffer-str 1))

(provide 'jao-mpdn)
;;; jao-mpdn.el ends here
