#!/usr/bin/env python

# Deejayd, a media player daemon
# Copyright (C) 2007-2008 Mickael Royer <mickael.royer@gmail.com>
#                         Alexandre Rossi <alexandre.rossi@gmail.com>
#
# 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 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, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

import sys
from optparse import OptionParser
import socket

from deejayd.net.client import DeejayDaemonSync, DeejaydError,\
                               DeejaydWebradioList,DeejaydPlaylist,\
                               DeejaydQueue,ConnectError

class DjcError(Exception): pass

class AvailableCommands:

    def __init__(self, server):
        self.server = server

    def playtoggle(self, args):
        """Toggle play/pause"""
        self.server.play_toggle().get_contents()

    def stop(self, args):
        """Stop player"""
        self.server.stop().get_contents()

    def previous(self, args):
        """Previous element in player"""
        self.server.previous().get_contents()

    def next(self, args):
        """Next element in player"""
        self.server.next().get_contents()

    def seek(self, args):
        """Set the position in the stream to argument value"""
        try: pos = int(args[0])
        except (ValueError, IndexError):
            raise DjcError('Bad command line')
        self.server.seek(pos).get_contents()

    def current(self, args):
        """Return the current playing media (if ti exists)"""
        cur = self.server.get_current().get_medias()
        if len(cur) == 0:
            print "No current media"
        else:
            media = cur[0]
            for (k, v) in media.items():
                print "%s: %s" % (k, v)

    def volume(self, args):
        """Set volume to argument value.
             If preceeded with 'up'|'down', (in|dea)crease volume with value."""
        try:
            if args[0] in ['up', 'down']:
                volume = self.server.get_status()['volume']
                possible_delta = int(args[1])
                if args[0] == 'up':
                    volume += possible_delta
                elif args[0] == 'down':
                    volume -= possible_delta
            else:
                volume = int(args[0])
            self.server.set_volume(volume).get_contents()
        except (ValueError, IndexError):
            raise DjcError('Bad command line')

    def set_option(self, args):
        """Set option to argument value. ex: djc set_option random 1"""
        try:
            option_name = args[0]
            option_value = int(args[1])
        except (ValueError, IndexError):
            raise DjcError('Bad command line')
        self.server.set_option(option_name,option_value).get_contents()

    def set_mode(self, args):
        """Set active mode to argument value. ex: djc set_mode webradio"""
        try: mode = args[0]
        except IndexError:
            raise DjcError('You need to choose a mode')
        else:
            self.server.set_mode(mode).get_contents()

    def player_option(self, args):
        """set player option
           ex: djc player_option option_name option_value
           option_name can be : sub_offset, av_offset, audio_lang, sub_lang"""
        try:
            opt_name = args[0]
            opt_value = args[1]
        except IndexError:
            raise DjcError('Usage: djc player_option option_name option_value')
        else:
            self.server.set_player_option(opt_name, opt_value).get_contents()

    def status(self, args):
        """Get full deejayd status"""
        for (key, value) in self.server.get_status().items():
            print key, ':', value

    def stats(self, args):
        """Get audio/video library stats"""
        for (key, value) in self.server.get_stats().items():
            print key, ':', value

    def audio_update(self, args):
        """Update audio library"""
        for (key, value) in self.server.update_audio_library().items():
            print key, ':', value

    def get_audio_dir(self, args):
        """Get the content of an directory in audio library.
           ex: djc get_audio_dir "dirname"
           if no dirname has been entered, return root directory content"""
        try: dirname = args[0]
        except IndexError: dirname = ""

        rsp = self.server.get_audio_dir(dirname)
        for dir in rsp.get_directories(): print "directory:", dir
        for file in rsp.get_files(): print "file:", file["filename"]

    def audio_search(self, args):
        """Search in audio library
           ex: djc audio_search type search_txt
           type has to be in ('all','artist','album','genre','title')"""
        try: type = args[0]
        except IndexError:
            raise DjcError('You need to enter a search type')
        try: search_txt = args[1]
        except IndexError:
            raise DjcError('You need to enter a search text')
        rsp = self.server.audio_search(search_txt, type)
        for file in rsp.get_files():
            print "file:", file["filename"]

# Video commands
    def video_update(self, args):
        """Update video library"""
        for (key, value) in self.server.update_video_library().items():
            print key, ':', value

    def get_video_dir(self, args):
        """Get the content of an directory in video library.
           ex: djc get_video_dir "dirname"
           if no dirname has been entered, return root directory content"""
        try: dirname = args[0]
        except IndexError: dirname = ""

        rsp = self.server.get_video_dir(dirname)
        for dir in rsp.get_directories(): print "directory:", dir
        for file in rsp.get_files(): print "file:", file["filename"]

    def video_info(self, args):
        """ Get video list's content """
        contents = self.server.get_video().get()
        for media in contents.get_medias():
            print media["pos"], '|', media["title"], '|',\
                  media["videowidth"], '|',\
                  media["videoheight"], '|', media["id"]

    def set_video(self, args):
        """Update the video list
           ex: djc set_video "type" "value"
           type must be :
             * directory to set content of dir "value" as video list
             * search to set result of search "value" as video list"""
        try: type = args[0]
        except IndexError:
            raise DjcError('You have to choose a type')
        try: value = args[1]
        except IndexError:
            raise DjcError('You have to enter a value')
        self.server.get_video().set(value, type).get_contents()

# Queue commands
    def queue_info(self, args):
        """ Get queue's content """
        contents = DeejaydQueue(self.server).get()
        for media in contents.get_medias():
            print media["pos"], '|', media["title"], '|',\
              media["artist"], '|',\
              media["album"], '|', media["id"]

    def queue_clear(self, args):
        """ clear queue """
        DeejaydQueue(self.server).clear().get_contents()

    def queue_add(self, args):
        """ add audio dirs/files to queue
            ex: djc queue_add dir1,dir2 """
        try: item = args[0]
        except IndexError:
            raise DjcError('You have to enter dirs/files')
        else: items = item.split(",")
        DeejaydQueue(self.server).add_medias(items).get_contents()

    def queue_loadpls(self, args):
        """ load playlist in the queue
            ex: djc queue_loadpls playlist1,playlist2"""
        try: playlist = args[0]
        except IndexError:
            raise DjcError('You have to enter playlist names')
        else: playlists = playlist.split(",")
        queue_obj = DeejaydQueue(self.server)
        queue_obj.load_playlists(playlists).get_contents()

    def queue_remove(self, args):
        """ remove songs from queue
            ex: djc queue_remove song_id1,song_id2 """
        try: item = args[0]
        except IndexError:
            raise DjcError('Enter song_id please')
        else:
            ids = item.split(",")
            try: ids = [int(id) for id in ids]
            except ValueError:
                raise DjcError("song_id has to be an integer")
        DeejaydQueue(self.server).del_songs(ids).get_contents()

# Playlist commands
    def __get_pl_obj(self, args, arg_pos = 0):
        try: pl_name = args[arg_pos]
        except IndexError:
            pl_name = None
        return DeejaydPlaylist(self.server, pl_name)

    def playlist_save(self, args):
        """ Save current playlist
            usage : djc playlist_save pl_name"""
        try: pl_name = args[0]
        except IndexError:
            raise DjcError('You have to enter a playlist name')
        DeejaydPlaylist(self.server, None).save(pl_name).get_contents()

    def playlist_erase(self, args):
        """ Erase a recorded playlist
            usage : djc playlist_erase pl_name"""
        try: pl_name = args[0]
        except IndexError:
            raise DjcError('You have to enter a playlist name')
        self.server.erase_playlist([pl_name]).get_contents()

    def playlist_list(self, args):
        """ Return list of recorded playlist """
        contents = self.server.get_playlist_list()
        for media in contents.get_medias():
            print media["name"]

    def playlist_info(self, args):
        """ Get playlist's content
            ex: djc playlist_info pl_name
            if no name has been entered, return content of the current pl"""
        contents = self.__get_pl_obj(args).get()
        for media in contents.get_medias():
            print media["pos"], '|', media["title"], '|', media["artist"], '|',\
                  media["album"], '|', media["id"]

    def playlist_clear(self, args):
        """ clear playlist
            ex: djc playlist_clear pl_name
            if no name has been entered, clear the current pl"""
        self.__get_pl_obj(args).clear().get_contents()

    def playlist_shuffle(self, args):
        """ shuffle playlist
            ex: djc playlist_shuffle pl_name
            if no name has been entered, shuffle the current pl"""
        self.__get_pl_obj(args).shuffle().get_contents()

    def playlist_add(self, args):
        """ add dirs/files to playlist
            ex: djc playlist_add dir1,dir2 pl_name
            if no pl_name has been entered, add to the current pl"""
        try: item = args[0]
        except IndexError:
            raise DjcError('You have to enter dirs/files')
        else: items = item.split(",")
        self.__get_pl_obj(args, 1).add_songs(items).get_contents()

    def playlist_load(self, args):
        """ load playlist in the main playlist
            ex: djc playlist_load playlist1,playlist2"""
        try: playlist = args[0]
        except IndexError:
            raise DjcError('You have to enter playlist names')
        else: playlists = playlist.split(",")
        pls_obj = DeejaydPlaylist(self.server)
        pls_obj.loads(playlists).get_contents()

    def playlist_remove(self, args):
        """ remove songs from playlist
            ex: djc playlist_remove song_id1,song_id2 pl_name
            if no pl_name has been entered, remove from the current pl"""
        try: item = args[0]
        except IndexError:
            raise DjcError('Enter song_id please')
        else:
            ids = item.split(",")
            try: ids = [int(id) for id in ids]
            except ValueError:
                raise DjcError("song_id has to be an integer")
        self.__get_pl_obj(args, 1).del_songs(ids).get_contents()

# Webradio commands
    def webradio_list(self, args):
        """ List webradios """
        wrs = DeejaydWebradioList(self.server).get()
        for wr in wrs.get_medias():
            print wr["title"],"|",wr["url"],"|",wr["id"]

    def webradio_add(self, args):
        """Add a webradio. ex: djc add_webradio wr_name url"""
        try:
            wr_name = args[0]
            wr_url = args[1]
        except IndexError:
            raise DjcError('Bad command line')
        wr = DeejaydWebradioList(self.server)
        wr.add_webradio(wr_name,wr_url).get_contents()

    def webradio_clear(self, args):
        """Erase all webradios"""
        DeejaydWebradioList(self.server).clear().get_contents()

    def webradio_delete(self, args):
        """Erase webradio(s)
           ex: djc webradio_erase wr_id1,wr_id2"""
        try: item = args[0]
        except IndexError:
            raise DjcError('Enter webradio_id please')
        else:
            ids = item.split(",")
            try: ids = [int(id) for id in ids]
            except ValueError:
                raise DjcError("webradio_id has to be an integer")
        wr = DeejaydWebradioList(self.server)
        wr.delete_webradios(ids).get_contents()

# dvd commands
    def dvd_reload(self, args):
        """Reload the dvd"""
        ans = self.server.dvd_reload()
        ans.get_contents()

    def dvd_get_content(self, args):
        """Get contents of the current dvd"""
        ans = self.server.get_dvd_content()
        dvd_content = ans.get_dvd_contents()
        print """
DVD content
title : %s
longest_track : %s
""" % (dvd_content["title"],dvd_content["longest_track"])
        for t in dvd_content["track"]:
            print """
  track : %s (%s)
""" % (t['ix'], t['length'])


def get_cmds():
    cmds = []
    for cmd_name in dir(AvailableCommands):
        if cmd_name[0] != '_':
            cmd = getattr(AvailableCommands, cmd_name)
            cmds.append(' : '.join([cmd_name, cmd.__doc__]))
    return cmds


cmd_sep = "\n  * "
cmds = cmd_sep.join(get_cmds())
usage = """usage: %prog [options] COMMAND [COMMAND_OPTIONS]
where COMMAND may be :""" + cmd_sep + cmds

parser = OptionParser(usage=usage)
parser.add_option("", "--host",
                  action="store", type="string",
                  dest="host", default="localhost",
                  help="Hostname or ip address on which deejayd listens. Default is localhost.")
parser.add_option("", "--port",
                  action="store", type="int",
                  dest="port", default=6800,
                  help="Port on which deejayd listens. Default is 6800.")
(options, args) = parser.parse_args()

def fail_cmdline():
    parser.print_help()
    sys.exit("Bad command line.")

if __name__ == '__main__':

    deejayd = DeejayDaemonSync()

    if len(args) < 1:
        fail_cmdline()

    command = args[0]

    cmds = AvailableCommands(deejayd)
    if command in dir(cmds):
        try: deejayd.connect(options.host, options.port)
        except ConnectError, msg:
            print msg
        else:
            try: getattr(AvailableCommands, command)(cmds, args[1:])
            except DeejaydError, msg:
                print "Deejayd Error:", msg
            except DjcError, msg:
                print "Djc Error:", msg
            except socket.error:
                print "Error: the server closes the socket"
            try: deejayd.disconnect()
            except socket.error:
                pass
    else:
        fail_cmdline()


# vim: ts=4 sw=4 expandtab
