#!/usr/bin/python

#Audio Tools, a module and set of tools for manipulating audio data
#Copyright (C) 2007-2010  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 os
import audiotools
import gettext

gettext.install("audiotools",unicode=True)

if (__name__ == '__main__'):
    parser = audiotools.OptionParser(
        usage=_(u"%prog [options] [track #] [track #] ..."),
        version="Python Audio Tools %s" % (audiotools.VERSION))

    parser.add_option('-V','--verbose',
                      action='store',
                      dest='verbosity',
                      choices=["quiet","normal","debug"],
                      default="normal",
                      help=_(u'the verbosity level to execute at'))

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

    parser.add_option('-s','--speed',action='store',
                      type='int',dest='speed')

    conversion = audiotools.OptionGroup(parser,_(u"Conversion Options"))

    conversion.add_option('-t','--type',
                          action='store',
                          dest='type',
                          choices=audiotools.TYPE_MAP.keys(),
                          default='wav',
                          help=_(u'the type of audio track to create'))

    conversion.add_option('-q','--quality',
                          action='store',
                          type='string',
                          dest='quality',
                          help=_(u'the quality to store audio tracks at'))

    conversion.add_option("-d","--dir",action='store',default='.',
                          dest='dir',
                          help=_(u"the directory to store extracted audio tracks"))

    conversion.add_option('--format',
                          action='store',
                          type='string',
                          default=None,
                          dest='format',
                          help=_(u'the format string for new filenames'))

    parser.add_option_group(conversion)

    metadata = audiotools.OptionGroup(parser,_(u"Metadata Options"))

    metadata.add_option('-x','--xmcd',
                        action='store',
                        type='string',
                        dest='xmcd',
                        metavar='FILENAME',
                        help=_(u'FreeDB XMCD file or MusicBrainz XML file'))

    metadata.add_option('--album-number',
                        dest='album_number',
                        action='store',
                        type='int',
                        default=0,
                        help=_(u'the album number of this CD, if it is one of a series of albums'))

    metadata.add_option('--album-total',
                        dest='album_total',
                        action='store',
                        type='int',
                        default=0,
                        help=_(u'the total albums of this CD\'s set, if it is one of a series of albums'))

    #if adding ReplayGain is a lossless process
    #(i.e. added as tags rather than modifying track data)
    #add_replay_gain should default to True
    #if not, add_replay_gain should default to False
    #which is which depends on the track type
    metadata.add_option('--replay-gain',
                        action='store_true',
                        dest='add_replay_gain',
                        help=_(u'add ReplayGain metadata to newly created tracks'))

    metadata.add_option('--no-replay-gain',
                        action='store_false',
                        dest='add_replay_gain',
                        help=_(u'do not add ReplayGain metadata in newly created tracks'))

    parser.add_option_group(metadata)

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

    #get the AudioFile class we are converted to
    AudioType = audiotools.TYPE_MAP[options.type]

    if (options.add_replay_gain is None):
        options.add_replay_gain = AudioType.lossless_replay_gain()

    #ensure the selected compression is compatible with that class
    if (options.quality == 'help'):
        if (len(AudioType.COMPRESSION_MODES) > 1):
            msg.info(_(u"Available compression types for %s:") % \
                         (AudioType.NAME))
            for mode in AudioType.COMPRESSION_MODES:
                msg.info(mode.decode('ascii'))
        else:
            msg.error(_(u"Audio type %s has no compression modes") % \
                          (AudioType.NAME))
        sys.exit(0)
    elif (options.quality is None):
        options.quality = AudioType.DEFAULT_COMPRESSION
    elif (options.quality not in AudioType.COMPRESSION_MODES):
        msg.error(_(u"\"%(quality)s\" is not a supported compression mode for type \"%(type)s\"") % \
                        {"quality":options.quality,
                         "type":AudioType.NAME})
        sys.exit(1)


    #if we're using an XMCD file, use that file for MetaData
    if (options.xmcd is not None):
        try:
            xmcd = audiotools.read_metadata_file(options.xmcd)
        except audiotools.MetaDataFileException,err:
            msg.error(unicode(err))
            sys.exit(1)
    else: #if we're not using an XMCD file, no MetaData
        xmcd = None

    quality = options.quality
    base_directory = options.dir

    try:
        cdda = audiotools.CDDA(options.cdrom,options.speed)
    except IOError, err:
        msg.error(unicode(err) + _(u". Is that an audio cd ?"))
        sys.exit(-1)

    if (len(cdda) == 0):
        msg.error(_(u"No CD in drive"))
        sys.exit(1)

    encoded = []

    if (len(args) == 0):
        to_rip = [track for track in cdda]
    else:
        to_rip = []
        for arg in args:
            try:
                to_rip.append(cdda[int(arg)])
            except IndexError:
                continue
            except ValueError:
                continue
        to_rip.sort(lambda x,y: cmp(x.track_number,y.track_number))

    for (track_number,cd_track) in enumerate(to_rip):
        basename = "track%2d%2.2d" % (options.album_number,
                                      track_number + 1)

        try:
            if (xmcd is not None):  #we have metadata
                try:
                    metadata = xmcd[cd_track.track_number]
                    if (options.album_number != 0):
                        metadata.album_number = options.album_number
                    if (options.album_total != 0):
                        metadata.album_total = options.album_total
                except KeyError:
                    metadata = None

                filename = os.path.join(
                    base_directory,
                    AudioType.track_name(file_path=basename,
                                         track_metadata=metadata,
                                         format=options.format))

                audiotools.make_dirs(filename)

                track = AudioType.from_pcm(
                    filename,
                    cd_track,
                    quality)

                track.set_metadata(metadata)
                encoded.append(track)
            else:               #no metadata
                filename = os.path.join(
                    base_directory,
                    AudioType.track_name(file_path=basename,
                                         track_metadata=None,
                                         format=options.format))

                audiotools.make_dirs(filename)

                track = AudioType.from_pcm(
                    filename,
                    cd_track,
                    quality)

                #even if no MetaData is given,
                #set track number and album number if possible
                track.set_metadata(audiotools.MetaData(
                        track_number=cd_track.track_number,
                        track_total=len(cdda),
                        album_number=options.album_number,
                        album_total=options.album_total))

                encoded.append(track)

            msg.info(_(u"track %(track_number)2.2d: %(log)s") % \
                         {"track_number":cd_track.track_number,
                          "log":str(cd_track.rip_log)})
            msg.info(_(u"track %(track_number)2.2d -> %(filename)s") % \
                         {"track_number":cd_track.track_number,
                          "filename":msg.filename(track.filename)})
        except audiotools.UnsupportedTracknameField,err:
            err.error_msg(msg)
            sys.exit(1)
        except KeyError:
            continue
        except audiotools.InvalidFormat,err:
            msg.error(unicode(err))
            sys.exit(1)
        except audiotools.EncodingError,err:
            msg.error(_(u"Unable to write \"%s\"") % (msg.filename(filename)))
            sys.exit(1)

    cdda.close()

    if (options.add_replay_gain and AudioType.can_add_replay_gain()):
        if (AudioType.lossless_replay_gain()):
            msg.info(_(u"Adding ReplayGain metadata.  This may take some time."))
        else:
            msg.info(_(u"Applying ReplayGain.  This may take some time."))
        try:
            AudioType.add_replay_gain([track.filename for track in encoded])
        except ValueError,err:
            msg.error(unicode(err))
            sys.exit(1)

