#!/usr/bin/python

#Audio Tools, a module and set of tools for manipulating audio data
#Copyright (C) 2007-2012  Brian Langenberger

#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
import time
import select
import os
import tty
import termios
import cStringIO
import audiotools
import audiotools.ui
import audiotools.player
import audiotools.text as _

if (audiotools.ui.AVAILABLE):
    urwid = audiotools.ui.urwid

    class CDplayGUI(audiotools.ui.PlayerGUI):
        def __init__(self, cdda, metadata, track_list, audio_output):
            self.cdda = cdda

            audiotools.ui.PlayerGUI.__init__(
                self,
                audiotools.player.CDPlayer(
                    cdda=cdda,
                    audio_output=audio_output,
                    next_track_callback=self.next_track),
                [(metadata[track.track_number].track_name
                  if (metadata[track.track_number].track_name is not None)
                  else (u"track %2.2d" % (track.track_number)),
                  track.length() / 75,
                  (track, metadata[track.track_number]))
                 for track in track_list],
                cdda.length() / 75)

        def select_track(self, radio_button, new_state, user_data,
                         auto_play=True):
            if (new_state):
                (track, metadata) = user_data

                if (metadata is not None):
                    self.update_metadata(
                        track_name=metadata.track_name,
                        album_name=metadata.album_name,
                        artist_name=metadata.artist_name,
                        track_number=track.track_number,
                        track_total=len(self.cdda),
                        pcm_frames=track.length() * 588,
                        channels=2,
                        sample_rate=44100,
                        bits_per_sample=16)
                else:
                    self.update_metadata(
                        track_total=len(self.cdda),
                        pcm_frames=track.length() * 588,
                        channels=2,
                        sample_rate=44100,
                        bits_per_sample=16)

                self.player.open(track.track_number)
                if (auto_play):
                    self.player.play()
                    self.play_pause_button.set_label(_.LAB_PAUSE_BUTTON)

    interactive_available = True
else:
    interactive_available = False


class CDplayTTY(audiotools.ui.PlayerTTY):
    def __init__(self, cdda, track_list, audio_output):
        self.track_index = -1
        self.track_list = track_list
        self.cdda = cdda
        audiotools.ui.PlayerTTY.__init__(
            self,
            audiotools.player.CDPlayer(
                cdda=cdda,
                audio_output=audio_output,
                next_track_callback=self.next_track))

    def previous_track(self):
        if (self.track_index > 0):
            self.track_index -= 1
            current_track = self.track_list[self.track_index]
            self.set_metadata(
                track_number=self.track_index + 1,
                track_total=len(self.cdda),
                channels=2,
                sample_rate=44100,
                bits_per_sample=16)
            self.player.open(current_track.track_number)
            self.player.play()

    def next_track(self):
        try:
            self.track_index += 1
            current_track = self.track_list[self.track_index]
            self.set_metadata(
                track_number=self.track_index + 1,
                track_total=len(self.cdda),
                channels=2,
                sample_rate=44100,
                bits_per_sample=16)
            self.player.open(current_track.track_number)
            self.player.play()
        except IndexError:
            self.playing_finished = True


if (__name__ == '__main__'):
    parser = audiotools.OptionParser(
        usage=_.USAGE_CDPLAY,
        version="Python Audio Tools %s" % (audiotools.VERSION))

    parser.add_option(
        '-I', '--interactive',
        action='store_true',
        default=False,
        dest='interactive',
        help=_.OPT_INTERACTIVE_PLAY)

    players_map = dict([(player.NAME, player)
                        for player in audiotools.player.AUDIO_OUTPUT])

    parser.add_option(
        '-o', '--output',
        action='store',
        dest='output',
        choices=[player.NAME for player in audiotools.player.AUDIO_OUTPUT
                 if player.available()],
        default=[player.NAME for player in audiotools.player.AUDIO_OUTPUT
                 if player.available()][0],
        help=(_.OPT_OUTPUT_PLAY %
              u", ".join([u"\"%s\"" % (player.NAME.decode('ascii'))
                          for player in audiotools.player.AUDIO_OUTPUT
                          if player.available()])))

    parser.add_option(
        '-c', '--cdrom', action='store',
        type='string', dest='cdrom',
        default=audiotools.DEFAULT_CDROM)

    parser.add_option(
        '--shuffle', action='store_true', dest='shuffle', default=False,
        help='shuffle tracks')

    parser.add_option(
        '-V', '--verbose',
        action='store',
        dest='verbosity',
        choices=audiotools.VERBOSITY_LEVELS,
        default=audiotools.DEFAULT_VERBOSITY,
        help=_.OPT_VERBOSE)

    lookup = audiotools.OptionGroup(parser, _.OPT_CAT_CD_LOOKUP)

    lookup.add_option(
        '--musicbrainz-server', action='store',
        type='string', dest='musicbrainz_server',
        default=audiotools.MUSICBRAINZ_SERVER,
        metavar='HOSTNAME')
    lookup.add_option(
        '--musicbrainz-port', action='store',
        type='int', dest='musicbrainz_port',
        default=audiotools.MUSICBRAINZ_PORT,
        metavar='PORT')
    lookup.add_option(
        '--no-musicbrainz', action='store_false',
        dest='use_musicbrainz',
        default=audiotools.MUSICBRAINZ_SERVICE,
        help=_.OPT_NO_MUSICBRAINZ)

    lookup.add_option(
        '--freedb-server', action='store',
        type='string', dest='freedb_server',
        default=audiotools.FREEDB_SERVER,
        metavar='HOSTNAME')
    lookup.add_option(
        '--freedb-port', action='store',
        type='int', dest='freedb_port',
        default=audiotools.FREEDB_PORT,
        metavar='PORT')
    lookup.add_option(
        '--no-freedb', action='store_false',
        dest='use_freedb',
        default=audiotools.FREEDB_SERVICE,
        help=_.OPT_NO_FREEDB)

    parser.add_option_group(lookup)

    (options, args) = parser.parse_args()
    msg = audiotools.Messenger("trackplay", options)

    if (options.interactive and (not interactive_available)):
        msg.error(_.ERR_URWID_REQUIRED)
        msg.output(_.ERR_GET_URWID1)
        msg.output(_.ERR_GET_URWID2)
        sys.exit(1)

    try:
        cdda = audiotools.CDDA(options.cdrom, perform_logging=False)
    except IOError, err:
        msg.error(unicode(err) + _.ERR_INVALID_CDDA)
        sys.exit(-1)

    if (len(cdda) == 0):
        msg.error(ERR_NO_CDDA)
        sys.exit(1)

    if (len(args) == 0):
        tracks = [cdda[i] for i in xrange(1, len(cdda) + 1)]
    else:
        tracks = []
        for tracknum in args:
            try:
                tracks.append(cdda[int(tracknum)])
            except (ValueError, IndexError):
                pass

    if (options.shuffle):
        import random

        random.shuffle(tracks)

    if (options.interactive):
        #a track_number -> MetaData dictionary
        #where track_number typically starts from 1
        metadata = dict(
            [(m.track_number, m) for m in
             cdda.metadata_lookup(
                 musicbrainz_server=options.musicbrainz_server,
                 musicbrainz_port=options.musicbrainz_port,
                 freedb_server=options.freedb_server,
                 freedb_port=options.freedb_port,
                 use_musicbrainz=options.use_musicbrainz,
                 use_freedb=options.use_freedb)[0]])

        cdplay = CDplayGUI(cdda=cdda,
                           metadata=metadata,
                           track_list=tracks,
                           audio_output=players_map[options.output]())
        if (len(cdda) > 0):
            cdplay.select_track(None, True,
                                (tracks[0],
                                 metadata[tracks[0].track_number]),
                                False)

        loop = urwid.MainLoop(cdplay,
                              audiotools.ui.style(),
                              unhandled_input=cdplay.handle_text)
        loop.set_alarm_at(tm=time.time() + 1,
                          callback=audiotools.ui.timer,
                          user_data=cdplay)

        try:
            loop.run()
            msg.ansi_clearscreen()
        except (termios.error, IOError):
            msg.error(_.ERR_TERMIOS_ERROR)
            msg.info(_.ERR_TERMIOS_SUGGESTION)
            msg.info(audiotools.ui.xargs_suggestion(sys.argv))
            sys.exit(1)
    else:
        trackplay = CDplayTTY(cdda=cdda,
                              track_list=tracks,
                              audio_output=players_map[options.output]())
        sys.exit(trackplay.run(msg, sys.stdin))
