# pylint: disable=C0111,R0903
# -*- coding: utf-8 -*-

"""Displays information about the current song in mpd.

Requires the following executable:
    * mpc

Parameters:
    * mpd.format: Format string for the song information.
      Supported tags (see `man mpc` for additional information)
        * {name}
        * {artist}
        * {album}
        * {albumartist}
        * {comment}
        * {composer}
        * {date}
        * {originaldate}
        * {disc}
        * {genre}
        * {performer}
        * {title}
        * {track}
        * {time}
        * {file}
        * {id}
        * {prio}
        * {mtime}
        * {mdate}
      Additional tags:
        * {position} - position of currently playing song
                       not to be confused with %position% mpc tag
        * {duration} - duration of currently playing song
        * {file1} - song file name without path prefix
                    if {file} = '/foo/bar.baz', then {file1} = 'bar.baz'
        * {file2} - song file name without path prefix and extension suffix
                    if {file} = '/foo/bar.baz', then {file2} = 'bar'
    * mpd.host: MPD host to connect to. (mpc behaviour by default)
    * mpd.layout: Space-separated list of widgets to add. Possible widgets are the buttons/toggles mpd.prev, mpd.next, mpd.shuffle and mpd.repeat, and the main display with play/pause function mpd.main.
"""

from collections import defaultdict

import string
import os

import bumblebee.util
import bumblebee.input
import bumblebee.output
import bumblebee.engine

from bumblebee.output import scrollable

class Module(bumblebee.engine.Module):
    def __init__(self, engine, config):
        super(Module, self).__init__(engine, config, [])

        self._layout = self.parameter("layout", "mpd.prev mpd.main mpd.next mpd.shuffle mpd.repeat")

        self._fmt = self.parameter("format", "{artist} - {title} {position}/{duration}")
        self._status = None
        self._shuffle = False
        self._repeat = False
        self._tags = defaultdict(lambda: '')

        if not self.parameter("host"):
            self._hostcmd = ""
        else:
            self._hostcmd = " -h " + self.parameter("host")

        # Create widgets
        widget_list = []
        widget_map = {}
        for widget_name in self._layout.split():
            widget = bumblebee.output.Widget(name=widget_name)
            widget_list.append(widget)

            if widget_name == "mpd.prev":
                widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "mpc prev" + self._hostcmd}
            elif widget_name == "mpd.main":
                widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "mpc toggle" + self._hostcmd}
                widget.full_text(self.description)
            elif widget_name == "mpd.next":
                widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "mpc next" + self._hostcmd}
            elif widget_name == "mpd.shuffle":
                widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "mpc random" + self._hostcmd}
            elif widget_name == "mpd.repeat":
                widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "mpc repeat" + self._hostcmd}
            else:
                raise KeyError("The mpd module does not support a {widget_name!r} widget".format(widget_name=widget_name))
        self.widgets(widget_list)

        # Register input callbacks
        for widget, callback_options in widget_map.items():
            engine.input.register_callback(widget, **callback_options)

    def hidden(self):
        return self._status is None

    @scrollable
    def description(self, widget):
        return string.Formatter().vformat(self._fmt, (), self._tags)

    def update(self, widgets):
        self._load_song()

    def state(self, widget):
        if widget.name == "mpd.shuffle":
            return "shuffle-on" if self._shuffle else "shuffle-off"
        if widget.name == "mpd.repeat":
            return "repeat-on" if self._repeat else "repeat-off"
        if widget.name == "mpd.prev":
            return "prev"
        if widget.name == "mpd.next":
            return "next"
        return self._status

    def _load_song(self):
        info = ""
        try:
            tags = ['name',
                    'artist',
                    'album',
                    'albumartist',
                    'comment',
                    'composer',
                    'date',
                    'originaldate',
                    'disc',
                    'genre',
                    'performer',
                    'title',
                    'track',
                    'time',
                    'file',
                    'id',
                    'prio',
                    'mtime',
                    'mdate']
            joinedtags = "\n".join(["tag {0} %{0}%".format(tag) for tag in tags])
            info = bumblebee.util.execute('mpc -f ' + '"' + joinedtags + '"' + self._hostcmd)
        except RuntimeError:
            pass
        self._tags = defaultdict(lambda: '')
        self._status = None
        for line in info.split("\n"):
            if line.startswith("[playing]"):
                self._status = "playing"
            elif line.startswith("[paused]"):
                self._status = "paused"

            if line.startswith("["):
                timer = line.split()[2]
                position = timer.split("/")[0]
                dur = timer.split("/")[1]
                duration = dur.split(" ")[0]
                self._tags.update({'position': position})
                self._tags.update({'duration': duration})

            if line.startswith("volume"):
                value = line.split("   ", 2)[1:]
                for option in value:
                    if option.startswith("repeat: on"):
                        self._repeat = True
                    elif option.startswith("repeat: off"):
                        self._repeat = False
                    elif option.startswith("random: on"):
                        self._shuffle = True
                    elif option.startswith("random: off"):
                        self._shuffle = False
            if line.startswith("tag"):
                key, value = line.split(" ", 2)[1:]
                self._tags.update({key: value})
                if key == "file":
                    self._tags.update({"file1": os.path.basename(value)})
                    self._tags.update(
                        {"file2":
                         os.path.splitext(os.path.basename(value))[0]})

# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
