#!/usr/bin/python2

# oggify -- Command-line interface for Oggify
# Copyright (c) 2008 Scott Paul Robertson (spr@scottr.org)
#
# This is part of Oggify (http://scottr.org/oggify/)
# 
# 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.

from oggify import Oggify, utils, version
from optparse import OptionParser
from os import path
import sys, os, tempfile, signal

etemp_file = None
dtemp_file = None

def handler(signum=0, frame=None):
    os.unlink(etemp_file)
    os.unlink(dtemp_file)
    sys.exit(-1)

def help(option, opt_str, value, parser):
    if len(parser.rargs) == 0:
        parser.print_help()
    else:
        try:
            plugin = utils.load_plugin(parser.rargs[0], "__doc__")
        except utils.OggifyError:
            print "Could not load help for %s" % parser.rargs[0]
            print parser.epilog
        if plugin.__doc__ == None:
            print "Could not load help for %s" % parser.rargs[0]
            print parser.epilog
        else:
            print plugin.__doc__
    sys.exit(0)

def setup_parser(parser):
    parser.add_option("-h", "--help", action="callback", type="string",
            nargs=0, help="show this help message or a plugin's and exit",
            metavar="[p]", callback=help)
    parser.add_option("-s", "--source", dest="source_plugin",
            metavar="plugin",
            help="Select the source format to use [default=%default]")
    parser.set_defaults(source_plugin="flac")
    parser.add_option("-o", "--output", dest="output_plugin",
            metavar="plugin",
            help="Select the output format to use [default=%default]")
    parser.set_defaults(output_plugin="ogg")
    parser.add_option("-v", "--verbose", action="store_true",
            dest="verbose", help="More detailed output.")
    parser.set_defaults(verbose=False)
    parser.add_option("-q", "--quality", type="int", dest="quality",
            help="Sets the quality to n (between 0 and 10) [default=%default]",
            metavar="n")
    parser.set_defaults(quality=5)
    parser.add_option("-L", "--follow-symlinks", action="store_true",
            dest="follow_symlinks", help="Follow symlinks in source tree")
    parser.set_defaults(follow_symlinks=False)
    parser.add_option("-n", "--nice", type="int", dest="nice",
            help="nice the tasks to n [default=%default]",
            metavar="n")
    parser.set_defaults(nice=10)
    parser.add_option("-p", "--pretend", action="store_true",
            dest="pretend", help="Print actions that will be performed")
    parser.set_defaults(pretend=False)
    parser.add_option("-P", "--purge", action="store_true", dest="purge",
            help="Remove unmatched files and dirs from destination")
    parser.set_defaults(purge=False)
    parser.add_option("-r", "--refresh", action="store_true", dest="refresh",
            help="Re-encode files that are older than the source file")
    parser.set_defaults(refresh=False)
    parser.add_option("-t", "--retag", action="store_true", dest="retag",
            help="Retag files that are older than the source file")
    parser.set_defaults(retag=False)
    parser.add_option("-c", "--clean", action="store_true", dest="clean",
            help="Remove files that are encoded in the incorrect format")
    parser.set_defaults(clean=False)

def verify_options(options):
    if options.quality < 0 or options.quality > 10:
        print >>sys.stderr, "Quality %s is not between 0 and 10" % options.quality
        return False
    if options.source_plugin not in utils.list_plugins('decode'):
        print >>sys.stderr, "%s not an input plugin" % options.source_plugin
        return False
    if options.output_plugin not in utils.list_plugins('encode'):
        print >>sys.stderr, "%s not an output plugin" % options.output_plugin
        return False
    if options.nice < -20 or options.nice > 19:
        print >>sys.stderr, "Nice value %s not between -20 and 18" % options.nice
        return False
    if options.retag and options.refresh:
        print >>sys.stderr, "--retag and --refresh are mutually exclusive"
        return False
    return True

def verify_args(args):
    if len(args) != 2:
        print >>sys.stderr, "Need to specify a source and destination only."
        return False
    if not os.path.exists(args[0]):
        print >>sys.stderr, "%s does not exist, not a valid src directory" % args[0]
        return False
    return True

def main(argv=sys.argv):
    usage = "%prog [options] <src> <dest>"
    plugins = """Input Plugins: %s Output Plugins: %s""" % (utils.list_plugins('decode'), utils.list_plugins('encode'))
    version_str = "%prog " + version
    parser = OptionParser(usage=usage, epilog=plugins, version=version_str,
            add_help_option=False)
    setup_parser(parser)

    options, args = parser.parse_args()

    if not verify_options(options):
        parser.print_help()
        return -1
    if not verify_args(args):
        parser.print_help()
        return -1

    decoder = utils.load_plugin(options.source_plugin, 'decode')
    encoder = utils.load_plugin(options.output_plugin, 'encode')

    tsuffix = "." + encoder.extension

    global etemp_file, dtemp_file
    (fd, etemp_file) = tempfile.mkstemp(suffix=tsuffix)
    os.close(fd)
    (fd, dtemp_file) = tempfile.mkstemp(suffix=".wav")
    os.close(fd)

    oggify = Oggify(args[0], args[1], options, decoder, encoder,
            etemp_file, dtemp_file)

    oggify.encode(not options.pretend)

    if options.refresh:
        oggify.reencode(not options.pretend)
    if options.retag:
        oggify.retag(not options.pretend)

    if options.clean or options.purge:
        oggify.clean(not options.pretend)
    if options.purge:
        oggify.purge(not options.pretend)

    os.unlink(etemp_file)
    os.unlink(dtemp_file)
    return 0

if __name__ == '__main__':
    signal.signal(signal.SIGINT, handler)
    signal.signal(signal.SIGHUP, handler)
    signal.signal(signal.SIGTERM, handler)
    sys.exit(main())
