#!/usr/bin/env python3
#
# Remote control for the Sonos sound system.
#
# Copyright (c) 2014, Matthias Friedrich <matt@mafr.de>
#
# 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 2, 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.
#
from __future__ import print_function
import argparse
import soco
import sys

# Hostname or IP address of your speaker.
DEFAULT_ZONE = 'Dave'

# Speaker volume cutoff for safety :)
MAX_VOLUME = 20


QUEUE_FMT = '{pos:3}. {item.creator} - {item.title}'
STATUS_FMT = '''\
{artist} - {title}
{album}
{position} - {duration}, pos {playlist_position}, vol {vol}\
'''

def mk_parser(subparsers, name, fun):
    parser = subparsers.add_parser(name)
    parser.set_defaults(fun=fun)
    return parser

def play(args):
    if args.verbose:
        print('playing')
    if args.track_no is None:
        args.dev.play()
    else:
        args.dev.play_from_queue(args.track_no)
    unmute(args)

def light(args):
    if args.dev.status_light:
        args.dev.status_light = 0
    else:
        args.dev.status_light = 1

def mute(args):
    args.dev.mute = 1

def unmute(args):
    args.dev.mute = 0

def toggle_mute(args):
    args.dev.mute = int(not args.dev.mute)

def volume(args):
    if args.volume is not None:
        vol = args.dev.volume + (1 if args.volume == '+' else -1)
        args.dev.volume = min(vol, MAX_VOLUME)
    print(args.dev.volume)

def status(args):
    print(STATUS_FMT.format(
        vol=args.dev.volume,
        **args.dev.get_current_track_info()
    ))

def queue(args):
    for pos, track in enumerate(args.dev.get_queue()):
        print(QUEUE_FMT.format(pos=pos, item=track))

def list_devs(args):
    for zone in soco.discover():
        zone.get_speaker_info(True)
        print(zone.speaker_info['mac_address'],
              zone.ip_address,
              zone.player_name)

def find_dev(zone_name):
    for zone in soco.discover():
        if zone_name in zone.player_name:
            return soco.SoCo(zone.ip_address)

def next(args):
    args.dev.next()

def previous(args):
    args.dev.previous()

def pause(args):
    if args.verbose:
        print('pausing')
    args.dev.pause()

parser = argparse.ArgumentParser()
parser.add_argument(
    '-z', '--zone',
    dest='zone',
    action='store',
    default=DEFAULT_ZONE,
    help='Specify zone name to use'
)
parser.add_argument(
    '-v', '--verbose',
    dest='verbose',
    action='store_true',
    help='Enable verbose mode'
)
subparsers = parser.add_subparsers()
mk_parser(subparsers, 'queue', queue)
mk_parser(subparsers, 'status', status)
mk_parser(subparsers, 'next', next)
mk_parser(subparsers, 'previous', previous)
mk_parser(subparsers, 'pause', pause)
mk_parser(subparsers, 'list', list_devs)

parser_play = subparsers.add_parser('play')
parser_play.add_argument('track_no', metavar='N', type=int, nargs='?',
                        help='Queue track number to play (0-based)')
parser_play.set_defaults(fun=play)

parser_volume = subparsers.add_parser('volume')
parser_volume.add_argument('volume', metavar='X', choices=('+', '-'), nargs='?',
                        help='Increase ("+") or decrese ("-") volume level')
parser_volume.set_defaults(fun=volume)

parser_mute = subparsers.add_parser('mute')
parser_mute.set_defaults(fun=mute)

parser_mute = subparsers.add_parser('unmute')
parser_mute.set_defaults(fun=unmute)

parser_mute = subparsers.add_parser('toggle_mute')
parser_mute.set_defaults(fun=toggle_mute)

parser_mute = subparsers.add_parser('light')
parser_mute.set_defaults(fun=light)


if __name__ == '__main__':
    parser.set_defaults(dev=None)
    args = parser.parse_args()
    device = find_dev(args.zone)
    if not device:
        print('Unknown device')
        sys.exit(1)
    args.dev = device
    if args.verbose:
        print(device.ip_address, device.player_name, '', end='')
    if hasattr(args, 'fun'):
        args.fun(args)
    else:
        parser.parse_args(['-h'])

# EOF
