#!/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 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))

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

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

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

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

    (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.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)

    #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

    quality = options.quality

    try:
        pcmdata = audiotools.PCMCat(iter([af.to_pcm() for af in audiofiles]))

        encoded = AudioType.from_pcm(options.filename,
                                     pcmdata,
                                     quality)

        encoded.set_metadata(metadata)

        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:
        msg.error(_(u"Unable to write \"%s\"") % \
                      (msg.filename(options.filename)))
        sys.exit(1)
    except audiotools.InvalidFormat,err:
        msg.error(unicode(err))
        sys.exit(1)
