#! /usr/bin/env python

# pyxmms-remote --- A command-line interface to XMMS, using PyXMMS
# Copyright (c) 2002, 2003 Florent Rougon
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
#
# 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; see the file COPYING. If not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
# MA 02111-1307, USA.

import sys, os, getopt, xmms
import xmms.control as xc

usage = """Usage: %s [option]... command [argument]...
Control a remote XMMS session.

Options:
  -s, --session                connect to the specified XMMS session
                               (default: 0)
  -p, --program                name of the XMMS exectutable for use by the
                               enqueue_and_play_launch_if_session_not_started,
                               also known as E, command (default: xmms)
  -f, --floats-precision       number of decimals displayed for floats
      --help                   display this message and exit""" % sys.argv[0]


# A generic exception class, base class of our specific exceptions
class error:
    def __init__(self, message=None):
        self.message = message
    def __str__(self):
        return "<%s: %s>" % (self.__class__.__name__, self.message)
    def complete_message(self):
        if self.message:
            return "%s: %s" % (self.ExceptionShortDescription, self.message)
        else:
            return "%s" % self.ExceptionShortDescription
    ExceptionShortDescription = "PyXMMS-remote generic exception"

# Exceptions defined by this module
class PyXMMSRemoteCmdLineDecodingError(error):
    ExceptionShortDescription = "Command-line decoding error"
# Base class for exceptions that we will catch in the end and display with a
# nice error message instead of the standard traceback.
class PyXMMSRemoteUserError(error):
    pass
class PyXMMSRemoteInvalidCommandError(PyXMMSRemoteUserError):
    ExceptionShortDescription = "Invalid command error"
class PyXMMSRemoteInvalidSyntax(PyXMMSRemoteUserError):
    ExceptionShortDescription = "Invalid syntax"


def handle_cmd(session, cmd, args, xmms_prg="xmms", floats_precision=2):
    if cmd == "playlist":
        xc.playlist(args[:-1], int(args[-1]))
    elif cmd == "get_version":
        print xc.get_version(session)
    elif cmd == "play_files":
        xc.play_files(args, session)
    elif cmd == "playlist_add":
        xc.playlist_add(args, session)
    elif cmd == "playlist_delete":
        xc.playlist_delete(int(args[0]), session)
    elif cmd == "play":
        xc.play(session)
    elif cmd == "pause":
        xc.pause(session)
    elif cmd == "stop":
        xc.stop(session)
    elif cmd == "play_pause":
        xc.play_pause(session)
    elif cmd == "is_playing":
        print xc.is_playing(session)
    elif cmd == "is_paused":
        print xc.is_paused(session)
    elif cmd == "get_playlist_pos":
        print xc.get_playlist_pos(session)
    elif cmd == "set_playlist_pos":
        xc.set_playlist_pos(int(args[0]), session)
    elif cmd == "get_playlist_length":
        print xc.get_playlist_length(session)
    elif cmd == "playlist_clear":
        xc.playlist_clear(session)
    elif cmd == "get_output_time":
        print "%s ms" % xc.get_output_time(session)
    elif cmd == "jump_to_time":
        xc.jump_to_time(int(args[0]), session)
    elif cmd == "get_volume":
        print "L: %d\nR: %d" % xc.get_volume(session)
    elif cmd == "get_main_volume":
        print xc.get_main_volume(session)
    elif cmd == "get_balance":
        print xc.get_balance(session)
    elif cmd == "set_volume":
        xc.set_volume(int(args[0]), int(args[1]), session)
    elif cmd == "set_main_volume":
        xc.set_main_volume(int(args[0]), session)
    elif cmd == "set_balance":
        xc.set_balance(int(args[0]), session)
    elif cmd == "get_skin":
        print xc.get_skin(session)
    elif cmd == "set_skin":
        xc.set_skin(args[0], session)
    elif cmd == "get_playlist_file":
        print xc.get_playlist_file(int(args[0]), session)
    elif cmd == "get_playlist_title":
        print xc.get_playlist_title(int(args[0]), session)
    elif cmd == "get_playlist_time":
        print xc.get_playlist_time(int(args[0]), session)
    elif cmd == "get_info":
        print "Rate: %d bps\nFrequency: %dHz\nNumber of channels: %d" \
              % xc.get_info(session)
    elif cmd in ("pl_win_toggle", "playlist_win_set_visible"):
        xc.pl_win_toggle(int(args[0]), session)
    elif cmd in ("eq_win_toggle", "equalizer_win_set_visible"):
        xc.eq_win_toggle(int(args[0]), session)
    elif cmd in ("main_win_toggle", "main_win_set_visible"):
        xc.main_win_toggle(int(args[0]), session)
    elif cmd == "is_main_win":
        print xc.is_main_win(session)
    elif cmd == "is_pl_win":
        print xc.is_pl_win(session)
    elif cmd == "is_eq_win":
        print xc.is_eq_win(session)
    elif cmd == "show_prefs_box":
        xc.show_prefs_box(session)
    elif cmd in ("toggle_aot", "set_always_on_top_state"):
        xc.toggle_aot(int(args[0]), session)
    elif cmd == "show_about_box":       # Does not work in XMMS 1.2.6
        xc.show_about_box(session)
    elif cmd == "eject":
        xc.eject(session)
    elif cmd == "playlist_prev":
        xc.playlist_prev(session)
    elif cmd == "playlist_next":
        xc.playlist_next(session)
    elif cmd in ("playlist_add_url_string", "add_url_to_playlist"):
        xc.playlist_add_url_string(args[0], session)
    elif cmd in ("playlist_ins_url_string", "insert_url_into_playlist_at_pos"):
        xc.playlist_ins_url_string(args[0], int(args[1]), session)
    elif cmd == "is_running":
        print xc.is_running(session)
    elif cmd == "toggle_repeat":
        xc.toggle_repeat(session)
    elif cmd == "toggle_shuffle":
        xc.toggle_shuffle(session)
    elif cmd == "is_repeat":
        print xc.is_repeat(session)
    elif cmd == "is_shuffle":
        print xc.is_shuffle(session)
    elif cmd == "get_eq":
        preamp, bands = xc.get_eq(session)
        bands_freqs = (60,170,310,600,1000,3000,6000,12000,14000,16000)
        msg = "Preamp: %+.*f dB\n" % (floats_precision, preamp)
        for i in range(len(bands)):
            msg = msg + "%5d Hz: %+.*f dB\n" % (bands_freqs[i],
                                                floats_precision,
                                                bands[i])
        sys.stdout.write(msg)           # No newline added
    elif cmd == "get_eq_preamp":
        print "%+.*f dB" % (floats_precision, xc.get_eq_preamp(session))
    elif cmd == "get_eq_band":
        print "%+.*f dB" % (floats_precision,
                            xc.get_eq_band(int(args[0]), session))
    elif cmd == "set_eq":
        xc.set_eq(float(args[0]), map(float, args[1:]), session)
    elif cmd == "set_eq_preamp":
        xc.set_eq_preamp(float(args[0]), session)
    elif cmd == "set_eq_band":
        xc.set_eq_band(int(args[0]), float(args[1]), session)
    elif cmd == "quit":
        xc.quit(session)
    # Here follow my own additions to the xmms_remote interface
    elif cmd in ("playlist_add_allow_relative", "a"):
        xc.playlist_add_allow_relative(args, session)
    elif cmd in ("enqueue_and_play", "e"):
        xc.enqueue_and_play(args, session)
    elif cmd in ("enqueue_and_play_launch_if_session_not_started", "E"):
        xc.enqueue_and_play_launch_if_session_not_started(args, xmms_prg,
                                                            session)
    elif cmd == "fade_out":
        default_action = "stop"
        default_nb_steps = 20
        default_step_duration = 0.5
        default_restore_volume = 1
        if len(args) == 0:
           xc.fade_out(default_action, default_nb_steps,
                         default_step_duration, default_restore_volume,
                         session)
        elif len(args) == 1:
            xc.fade_out(args[0], default_nb_steps, default_step_duration,
                          default_restore_volume, session)
        elif len(args) == 2:
            xc.fade_out(args[0], int(args[1]), default_step_duration,
                          default_restore_volume, session)
        elif len(args) == 3:
            xc.fade_out(args[0], int(args[1]), float(args[2]),
                          default_restore_volume, session)
        elif len(args) == 4:
            xc.fade_out(args[0], int(args[1]), float(args[2]),
                          int(args[3]), session)
        else:
            raise PyXMMSRemoteInvalidSyntax("invalid number of arguments for "
                                            "the fade_out command")
    else:
        raise PyXMMSRemoteInvalidCommandError(
            "command %s is invalid" % cmd)


def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], "f:s:p:",
                                   ["floats-precision=",
                                    "help",
                                    "session=",
                                    "program="])
    except getopt.GetoptError, message:
        sys.stderr.write(usage + "\n")
        sys.exit(1)

    # Default values for options
    floats_precision = 2
    session = 0
    xmms_prg = os.getenv("PYXMMS_REMOTE_XMMS_PRG", "xmms")
    
    for option, value in opts:
        if option in ("-f", "--floats-precision"):
            try:
                floats_precision = int(value)
            except ValueError:
                sys.stderr.write("Floats precision must be an integer\n")
                sys.exit(1)
        elif option in ("-p", "--program"):
            xmms_prg = value
        elif option in ("-s", "--session"):
            try:
                session = int(value)
            except ValueError:
                sys.stderr.write("Session must be an integer\n")
                sys.exit(1)
        elif option == "--help":
            print usage
            sys.exit(0)
        else:
            raise PyXMMSRemoteCmdLineDecodingError(
                "unexpected option received from the getopt module; "
                "probably a bug in %s" % sys.argv[0])

    if len(args) < 1:
        sys.stderr.write(usage + "\n")
        sys.exit(1)

    cmd = args[0]
    
    try:
        handle_cmd(session, cmd, args[1:], xmms_prg, floats_precision)
    except (PyXMMSRemoteUserError, xmms.error), exc_instance:
        sys.stderr.write("Error:\n\n%s\n" % exc_instance.complete_message())
    except (TypeError, ValueError, IndexError), msg:
        sys.stderr.write("Error: %s (probably caused by invalid arguments to "
                         "the %s command)\n" % (msg, cmd))
    
    sys.exit(0)


if __name__ == "__main__": main()
