#!/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 audiotools
import sys
import os
import os.path
import subprocess
import gettext

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

if (__name__ == '__main__'):
    parser = audiotools.OptionParser(
        usage=_(u'%prog [options] [-o output] <track 1> [track 2] ...'),
        version="Python Audio Tools %s" % (audiotools.VERSION))

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

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

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

    conversion.add_option('-o', '--output', dest='filename',
                          metavar='FILE',
                          help=_(u'the output file'))

    parser.add_option_group(conversion)

    parser.add_option('--cue',
                      action='store',
                      type='string',
                      dest='cuesheet',
                      metavar='FILENAME',
                      help=_(u'a cuesheet to embed in the output file'))

    parser.add_option('-V', '--verbose',
                      action='store',
                      dest='verbosity',
                      choices=audiotools.VERBOSITY_LEVELS,
                      default=audiotools.DEFAULT_VERBOSITY,
                      help=_(u'the verbosity level to execute at'))

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

    if (options.filename is None):
        msg.error(_(u'You must specify an output file'))
        sys.exit(1)

    #get the AudioFile class we are converted to
    if (options.type is not None):
        AudioType = audiotools.TYPE_MAP[options.type]
    else:
        try:
            AudioType = audiotools.filename_to_type(options.filename)
        except audiotools.UnknownAudioType, exp:
            exp.error_msg(msg)
            sys.exit(1)

    #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.new_row()
                if (mode == audiotools.__default_quality__(AudioType.NAME)):
                    msg.output_column(msg.ansi(mode.decode('ascii'),
                                               [msg.BOLD,
                                                msg.UNDERLINE]), True)
                else:
                    msg.output_column(mode.decode('ascii'), True)
                if (mode in AudioType.COMPRESSION_DESCRIPTIONS):
                    msg.output_column(u" : ")
                else:
                    msg.output_column(u"   ")
                msg.output_column(
                    AudioType.COMPRESSION_DESCRIPTIONS.get(mode, u""))
            msg.info_rows()
        else:
            msg.error(_(u"Audio type %s has no compression modes") % \
                          (AudioType.NAME))
        sys.exit(0)
    elif (options.quality is None):
        options.quality = audiotools.__default_quality__(AudioType.NAME)
    elif (options.quality not in AudioType.COMPRESSION_MODES):
        msg.error(_(u"\"%(quality)s\" is not a supported " +
                    u"compression mode for type \"%(type)s\"") %
                  {"quality": options.quality,
                   "type": AudioType.NAME})
        sys.exit(1)

    #grab the list of AudioFile objects we are converting from
    audiofiles = audiotools.open_files(args, messenger=msg)
    if (len(audiofiles) < 1):
        msg.error(_(u"You must specify at least 1 supported audio file"))
        sys.exit(1)

    if (len(set([f.sample_rate() for f in audiofiles])) != 1):
        msg.error(_(u"All audio files must have the same sample rate"))
        sys.exit(1)

    if (len(set([f.channels() for f in audiofiles])) != 1):
        msg.error(_(u"All audio files must have the same channel count"))
        sys.exit(1)

    if (len(set([int(f.channel_mask()) for f in audiofiles])) != 1):
        msg.error(_(u"All audio files must have the same channel assignment"))
        sys.exit(1)

    if (len(set([f.bits_per_sample() for f in audiofiles])) != 1):
        msg.error(_(u"All audio files must have the same bits per sample"))
        sys.exit(1)

    #if embedding a cuesheet, try to read it before doing any work
    if (options.cuesheet is not None):
        try:
            cuesheet = audiotools.read_sheet(options.cuesheet)
        except audiotools.SheetException, err:
            msg.error(unicode(err))
            sys.exit(1)
    else:
        cuesheet = None

    #constuct a MetaData object from our audiofiles
    track_metadatas = [f.get_metadata() for f in
                       audiofiles if (f.get_metadata() is not None)]

    if (len(track_metadatas) > 0):
        track_fields = dict([(field,
                              set([getattr(m, field)
                                   for m in track_metadatas]))
                             for field in audiotools.MetaData.FIELDS])

        metadata = audiotools.MetaData(**dict([(field, list(values)[0])
                                               for (field, values) in
                                               track_fields.items()
                                               if (len(values) == 1)]))

        #port over non-duplicate images
        images = []
        for m in track_metadatas:
            for i in m.images():
                if (i not in images):
                    images.append(i)
        for i in images:
            metadata.add_image(i)
    else:
        metadata = None

    progress = audiotools.SingleProgressDisplay(
        msg, msg.filename(options.filename))

    try:
        encoded = AudioType.from_pcm(
            options.filename,
            audiotools.PCMReaderProgress(
                audiotools.PCMCat(iter([af.to_pcm() for af in audiofiles])),
                sum([af.total_frames() for af in audiofiles]),
                progress.update),
            options.quality)

        encoded.set_metadata(metadata)

        progress.clear()

        if (cuesheet is not None):
            #set_metadata() will sometimes transfer a cuesheet automatically
            #in that case, don't transfer it again via set_cuesheet()
            existing_cuesheet = encoded.get_cuesheet()
            if (existing_cuesheet is None):
                encoded.set_cuesheet(cuesheet)

    except audiotools.EncodingError, err:
        msg.error(_(u"%(filename)s: %(error)s") %
                      {"filename": msg.filename(options.filename),
                       "error": err})
        sys.exit(1)
    except audiotools.InvalidFormat, err:
        msg.error(unicode(err))
        sys.exit(1)
