#! /usr/bin/python
#
# Licensed under the MIT license
# http://opensource.org/licenses/mit-license.php

# Copyright 2006,2007,2008 Frank Scholz <coherence@beebits.net>
# Copyright 2011, Hartmut Goebel <h.goebel@goebel-consult.de>

""" Coherence is a framework to host DLNA/UPnP devices

    For more information about it and its available backends
    point your browser to: http://coherence-project.org
"""

import os
import sys
import string

import warnings
warnings.filterwarnings('ignore', "extern.louie will soon be deprecated")
warnings.filterwarnings('ignore', "coherence.extern.inotify is deprecated.")

from coherence import __version__
from coherence.extern.simple_config import Config, ConfigItem



def daemonize():
    # thankfully taken from twisted.scripts._twistd_unix.py
    # See http://www.erlenstar.demon.co.uk/unix/faq_toc.html#TOC16
    if os.fork():   # launch child and...
        os._exit(0) # kill off parent
    os.setsid()
    if os.fork():   # launch child and...
        os._exit(0) # kill off parent again.
    os.umask(077)
    null = os.open('/dev/null', os.O_RDWR)
    for i in range(3):
        try:
            os.dup2(null, i)
        except OSError, e:
            if e.errno != errno.EBADF:
                raise
    os.close(null)


def setConfigFile():
    def findConfigDir():
        try:
            configDir = os.path.expanduser('~')
        except:
            configDir = os.getcwd()
        return configDir

    return os.path.join(findConfigDir(), '.coherence')


def __opt_option(option, opt, value, parser):
    try:
        key, val = value.split(':', 1)
    except:
        key = value
        val = ''
    parser.values.options[key] = val


def main(config):

    from coherence.base import Coherence
    c = Coherence(config)
    #c = Coherence(plugins={'FSStore': {'content_directory':'tests/content'},
    #                       'Player': {})
    #c.add_plugin('FSStore', content_directory='tests/content', version=1)




if __name__ == '__main__':

    import optparse


    class OptionParser(optparse.OptionParser):
        """
        Simple wrapper to add list of available plugins to help
        message, but only if help message is really printed
        """

        def print_help(self, file=None):
            from coherence.base import Plugins
            # hack: avoid plugins are displaying there help message
            sys.argv = sys.argv[:1]
            p = Plugins().keys()
            p.sort()
            self.epilog = 'Available backends are: %s' % ', '.join(p)
            optparse.OptionParser.print_help(self, file)

    parser = OptionParser('%prog [options]',
                          version="Coherence version: %s" % __version__)
    parser.add_option('-d', '--daemon', action='store_true',
                      help='daemonize')
    parser.add_option('--noconfig', action='store_false', dest='configfile',
                      help='ignore any configfile found')
    parser.add_option('-c', '--configfile', default=setConfigFile(),
                      help='configfile to use, default: %default')
    parser.add_option('-l', '--logfile', help='logfile to use')
    parser.add_option('-o', '--option', action='callback',
                      dest='options', metavar='NAME:VALUE',
                      default={}, callback=__opt_option, type='string',
                      help="activate option (name and value separated by a "
                           "colon (`:`), may be given multiple times)")
    parser.add_option('-p', '--plugins', action='append',
                      help='activate plugins (may be given multiple times) '
                           'Example: --plugin=backend:FSStore,name:MyCoherence')

    options, args = parser.parse_args()
    if args:
        parser.error('takes no arguments')

    if options.daemon:
        try:
            daemonize()
        except:
            print traceback.format_exc()

    config = {}
    config['logging'] = {}


    if options.configfile:
        try:
            config = Config(options.configfile, root='config',
                            element2attr_mappings={'active': 'active'}).config
        except SyntaxError:
            import traceback
            #print traceback.format_exc()
            try:
                from configobj import ConfigObj
                config = ConfigObj(options.configfile)
            except:
                print "hmm, seems we are in trouble reading in any sort of config file"
                print traceback.format_exc()
        except IOError:
            print "Config file %r not found, ignoring" % options.configfile
            pass


    if options.logfile:
        if isinstance(config, (ConfigItem, dict)):
            if 'logging' not in config:
                config['logging'] = {}
            config['logging']['logfile'] = options.logfile
        else:
            config['logfile'] = options.logfile

    # copy options passed by -o/--option into config
    for k, v in options.options.items():
        if k == 'logfile':
            continue
        config[k] = v

    if options.daemon:
        if isinstance(config, (ConfigItem, dict)):
            if not config.get('logging', None):
                config['logging'] = {}
            if not config['logging'].get('logfile', None):
                config['logging']['level'] = 'none'
                try:
                    del config['logging']['logfile']
                except KeyError:
                    pass
        else:
            if not config.get('logfile', None):
                config.set('logmode', 'none')
                try:
                    del config['logfile']
                except KeyError:
                    pass

    use_qt = config.get('qt', 'no') == 'yes'
    if (config.get('use_dbus', 'no') == 'yes' or
        config.get('glib', 'no') == 'yes' or
        use_qt or
        config.get('transcoding', 'no') == 'yes'):
        if use_qt:
            from coherence.extern import qt4reactor
            qt4reactor.install()
        else:
            try:
                from twisted.internet import glib2reactor
                glib2reactor.install()
            except AssertionError:
                print "error installing glib2reactor"

    if options.plugins:
        plugins = config.get('plugin')
        if isinstance(plugins, dict):
            config['plugin'] = [plugins]
        if not plugins:
            plugins = config.get('plugins', None)
        if not plugins:
            config['plugin'] = []
            plugins = config['plugin']

        while len(options.plugins) > 0:
            p = options.plugins.pop()
            plugin = {}
            plugin_conf = p.split(',')
            for pair in plugin_conf:
                pair = pair.split(':', 1)
                if len(pair) == 2:
                    pair[0] = pair[0].strip()
                    if pair[0] in plugin:
                        if not isinstance(plugin[pair[0]], list):
                            new_list = [plugin[pair[0]]]
                            plugin[pair[0]] = new_list
                        plugin[pair[0]].append(pair[1])
                    else:
                        plugin[pair[0]] = pair[1]
            try:
                plugins.append(plugin)
            except AttributeError:
                print "mixing commandline plugins and configfile does not work with the old config file format"

    from twisted.internet import reactor

    reactor.callWhenRunning(main, config)
    reactor.run()
