#!/usr/bin/env python

# Deejayd, a media player daemon
# Copyright (C) 2007-2008 Mickael Royer <mickael.royer@gmail.com>
#                         Alexandre Rossi <alexandre.rossi@gmail.com>
#
# 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.

"""
This is the script used to launch deejayd
"""

############ Parse Option ############################
######################################################
from optparse import OptionParser
usage = "usage: %prog [options]"
parser = OptionParser(usage=usage)

# List options
parser.set_defaults(pidfile="deejayd.pid",kill = False,daemon = True)
parser.add_option("-u","--uid",dest="uid",type="string",\
    help="the uid to run as")
parser.add_option("-g","--gid",dest="gid",type="string",\
    help="the gid to run as (the first one), and the supplementary gids separated by commas.")
parser.add_option("-n","--nodaemon",action="store_false",dest="daemon",\
    help="no daemonize deejayd")
parser.add_option("-l","--log-file",type="string",dest="logfile",\
    metavar="FILE", help="Specify the log file")
parser.add_option("-w","--webui-log",type="string",dest="webui_logfile",\
    metavar="FILE", help="Specify the log file for the webui")
parser.add_option("-p","--pid-file",type="string",dest="pidfile",\
    metavar="FILE", help="Specify the log file")
parser.add_option("-c","--conf-file",type="string",dest="conffile",\
    metavar="FILE", help="Specify a custom conf file")
parser.add_option("-k","--kill",action="store_true",dest="kill",\
    help="Kill the actual deejayd process")
parser.add_option("-d", "--debug",
                  action="store_true", dest="debug",
                  help="Log more debug informations")

(options, args) = parser.parse_args()
######################################################

# add custom config parms
import errno,random,sys,os,pwd,grp
from deejayd.ui.config import DeejaydConfig
if options.conffile:
    if os.path.isfile(options.conffile):
        DeejaydConfig.custom_conf = options.conffile
    else:
        sys.exit("The config file does not exist.")

if options.debug:
    DeejaydConfig().set('general', 'log', 'debug')


######################################################

def daemonize():
    # 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 killDeejayd(pidfile):
    if os.path.exists(pidfile):
        try: pid = int(open(pidfile).read())
        except ValueError:
            sys.exit('Pidfile %s contains non-numeric value' % pidfile)
        try:
            os.kill(pid, 15)
            removePID(pidfile)
        except OSError, err:
            sys.exit('Unable to stop deejayd : %s, are you sure it running ?'\
                ,(err,))
    else:
        sys.exit('no PidFile found, are you sure deejayd running ?')


def removePID(pidfile):
    try: os.unlink(pidfile)
    except OSError, e:
        if e.errno == errno.EACCES or e.errno == errno.EPERM:
            sys.exit("Unable to remove pid file : %s" % (e,))


def setEnv(options):
    # Init random generator
    random.seed()

    if options.daemon:
        daemonize()
    # Store the pid
    removePID(options.pidfile)
    open(options.pidfile,'wb').write(str(os.getpid()))

    if options.gid:
        gids = options.gid.split(',')
        ngids = []
        for gid in gids:
            try: ngid = int(gid)
            except ValueError:
                ngid = grp.getgrnam(gid)[2]
            ngids.append(ngid)
        try:
            os.setgroups(ngids)
            os.setgid(ngids[0])
        except OSError:
            sys.exit("Unable to change gid of the process")
    if options.uid:
        try: uid = int(options.uid)
        except ValueError:
            uid = pwd.getpwnam(options.uid)[2]
        try:
            os.setuid(uid)
        except OSError:
            sys.exit("Unable to change uid of the process")


def startLog(options):
    from twisted.python import log
    import deejayd.ui.log

    log_file_name = None
    if options.logfile:
        log_file_name = options.logfile
    elif options.daemon:
        log_file_name = 'deejayd.log'

    if log_file_name:
        flo = deejayd.ui.log.SignaledFileLogObserver(log_file_name)
        log.startLoggingWithObserver(flo.emit)
    else:
        log.startLogging(sys.stdout)


# Start
if __name__ == "__main__":
    if options.kill:
        killDeejayd(options.pidfile)
        sys.exit()

    ###################
    # install reactor
    ##################
    config = DeejaydConfig()
    media_backend = config.get("general", "media_backend")
    modes = config.get("general", "activated_modes").split(",")
    video_support = "video" in modes or "dvd" in modes
    if media_backend == "gstreamer":
        if video_support:
            # Install gtk2 reactor
            from twisted.internet import gtk2reactor
            gtk2reactor.install()
        else:
            # Install glib2 reactor
            from twisted.internet import glib2reactor
            glib2reactor.install()

    from twisted.internet import reactor
    ###############################################################

    setEnv(options)
    startLog(options)

    from twisted.internet.error import CannotListenError
    from twisted.python import log

    # init translation
    import gettext
    from deejayd.ui.i18n import DeejaydTranslations
    try: t = gettext.translation("deejayd", class_=DeejaydTranslations)
    except IOError:
        t = DeejaydTranslations()
    t.install()

    # start core
    from deejayd.core import DeejayDaemonCore
    deejayd_core = DeejayDaemonCore(config)

    service = False
    # net service
    if config.getboolean("net","enabled"):
        service = True
        from deejayd.net.deejaydProtocol import DeejaydFactory

        factory = DeejaydFactory(deejayd_core)
        port = config.getint("net", "port")
        for bind_address in config.get_bind_addresses('net'):
            try: reactor.listenTCP(port, factory, interface=bind_address)
            except CannotListenError, err:
                log.err(str(err))
                sys.exit(1)

    # webui service
    if config.getboolean("webui","enabled"):
        try:
            from deejayd.webui import twisted_handler as handler
        except ImportError:
            log.err("webui does not seem to be installed, disabling.")
            config.set("webui", "enabled", False)
        else:
            service = True
            try: site = handler.init(deejayd_core,config,options.webui_logfile)
            except handler.DeejaydWebError, err:
                log.err(err)
                sys.exit(1)

            port = config.getint("webui","port")
            for bind_address in config.get_bind_addresses('webui'):
                try: reactor.listenTCP(port, site, interface=bind_address)
                except CannotListenError, err:
                    log.err(str(err))
                    sys.exit(1)

    # launch reactor
    if not service:
        log.err("No service has been activated")
        sys.exit(1)
    reactor.addSystemEventTrigger('after','shutdown',deejayd_core.close)
    reactor.run()

# vim: ts=4 sw=4 expandtab
