#!/tmp/codtest/bin/python
#
# Hey Emacs, this is -*-python-*-
#
# Copyright 2013 Peter Liljenberg <peter.liljenberg@gmail.com>
#
# Distributed under an MIT license, please see LICENSE in the top dir.

import sys
import os
import argparse

from codplayer import player
from codplayer import config
from codplayer import db
from codplayer.state import StateError
from codplayer.command import CommandError, ClientError

def state_getter(cfg):
    for p in cfg.publishers:
        pg = p.getter()
        if pg:
            return pg

    return None


def state_publisher(cfg):
    for p in cfg.publishers:
        ps = p.subscriber()
        if ps:
            return ps

    return None


def main(args):
    try:
        cfg = config.PlayerConfig(args.config)
    except config.ConfigError, e:
        sys.exit('invalid configuration:\n{0}'.format(e))

    if args.command == 'state':
        pg = state_getter(cfg)
        if not pg:
            sys.exit('no way to get player state')

        print pg.get_state(timeout = args.timeout)

        if args.follow:
            ps = state_publisher(cfg)
            if not ps:
                sys.exit('no publisher supports subscribing to state updates')

            for obj in ps.iter(timeout = args.timeout):
                print obj


    elif args.command == 'source':
        pg = state_getter(cfg)
        if not pg:
            sys.exit('no way to get player state')

        print pg.get_disc(timeout = args.timeout)

    # All other commands get sent to the daemon
    else:
        cmd_args = []

        if args.command == 'disc':
            if args.id:
                if (db.Database.is_valid_disc_id(args.id) or
                    db.Database.is_valid_db_id(args.id)):
                    cmd_args.append(args.id)
                else:
                    sys.exit('invalid disc or db id: {0}'.format(args.id))


        # Try sending through one of the command channels
        for cf in cfg.commands:
            c = cf.client()
            try:
                ret = c.send(args.command, cmd_args, timeout = args.timeout)
            except CommandError, e:
                sys.exit('codplayerd: error: {1}'.format(c.__class__.__name__, e))
            except ClientError, e:
                sys.stderr.write('{0} error: {1}\n'.format(c.__class__.__name__, e))
            else:
                if ret:
                    print ret
                return

        sys.exit('failed sending command')


#
# Set up the command argument parsing
#

parser = argparse.ArgumentParser(description = 'codplayer daemon')
parser.add_argument('-c', '--config', help = 'alternative configuration file')
parser.add_argument('-t', '--timeout', type = int,
                    help = 'give up command/stop updates after TIMEOUT seconds')

subparsers = parser.add_subparsers(help = 'command', dest = 'command')

parser_state = subparsers.add_parser(
    'state', help = 'output current player state')
parser_state.add_argument('-f', '--follow', action = 'store_true',
                          help = 'follow state updates, if supported by the publisher')

parser_source = subparsers.add_parser(
    'source', help = 'get the current source disc as JSON')

parser_disc = subparsers.add_parser(
    'disc', help = 'notify player that a new disc has been inserted, or play disc from database')
parser_disc.add_argument('id', nargs = '?', help = 'Disc or database ID, if omitted inserted CD is played')

parser_play = subparsers.add_parser(
    'play', help = 'play stopped disc from start or resume paused disc')

parser_pause = subparsers.add_parser(
    'pause', help = 'pause playing disc')

parser_play_pause = subparsers.add_parser(
    'play_pause', help = 'toggle playing or pausing the disc')

parser_next = subparsers.add_parser(
    'next', help = 'go to the next track')

parser_prev = subparsers.add_parser(
    'prev', help = 'go to start of the track or the previous track')

parser_stop = subparsers.add_parser(
    'stop', help = 'stop playing the disc')

parser_eject = subparsers.add_parser(
    'eject', help = 'stop any playing disc and eject it')

parser_quit = subparsers.add_parser(
    'quit', help = 'tell player process to quit nicely')


if __name__ == '__main__':
    args = parser.parse_args()
    main(args)
