#!/usr/bin/env python

#   Copyright 2009-2016 Oli Schacher
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# main startup file

from __future__ import print_function

try:
    import configparser
except ImportError:
    import ConfigParser as configparser
from fuglu import FUGLU_VERSION
from fuglu.daemon import DaemonStuff
import logging
import logging.config
import fuglu.funkyconsole
from fuglu import loghandlers
import sys
from fuglu.core import MainController
import signal
import os
import pwd
import grp
import optparse

controller = None

theconfigfile = '/etc/fuglu/fuglu.conf'
dconfdir = '/etc/fuglu/conf.d'
theloggingfile = '/etc/fuglu/logging.conf'
thepidfile = '/var/run/fuglu.pid'

# register custom log handlers
logging.custom_handlers = loghandlers


def reloadconfig():
    """reload configuration file"""
    logger = logging.getLogger('fuglu')
    logger.info('Reloading configuration')
    newconfig = configparser.RawConfigParser()
    newconfig.readfp(open(theconfigfile))

    identifier = "no identifier given"
    if newconfig.has_option('main', 'identifier'):
        identifier = newconfig.get('main', 'identifier')

    # load conf.d
    if os.path.isdir(dconfdir):
        filelist = os.listdir(dconfdir)
        configfiles = [
            dconfdir + '/' + c for c in filelist if c.endswith('.conf')]
        logger.debug('Conffiles in %s: %s' % (dconfdir, configfiles))
        readfiles = newconfig.read(configfiles)
        logger.debug('Read additional files: %s' % (readfiles))

    logger.info('Reload config complete. Current configuration:%s' %
                identifier)
    controller.config = newconfig
    controller.propagate_core_defaults()

    logger.info('Reloading plugins...')
    ok = controller.load_plugins()
    if ok:
        logger.info('Plugin reload completed')
    else:
        logger.error('Plugin reload failed')

    controller.propagate_plugin_defaults()

    controller.reload()


def sighup(signum, frame):
    """handle sighup to reload config"""
    reloadconfig()

lint = False
debugmsg = False
console = False


parser = optparse.OptionParser(version=FUGLU_VERSION)
parser.add_option("--lint", action="store_true", dest="lint",
                  default=False, help="Check configuration and exit")
parser.add_option("--console", action="store_true", dest="console",
                  default=False, help="start an interactive console after fuglu startup")
parser.add_option("-f", "--foreground", action="store_true", dest="foreground", default=False,
                  help="start fuglu in the foreground, even if daemonize is enabled in the config")
parser.add_option("--pidfile", action="store", dest="pidfile",
                  help="use a different pidfile than /var/run/fuglu.pid")
parser.add_option("-c", "--config", action="store", dest="configfile",
                  help="use a different config file and disable reading from /etc/fuglu/conf.d")

(opts, args) = parser.parse_args()
if len(args) > 0:
    print("Unknown option(s): %s" % args)
    print("")
    parser.print_help()
    sys.exit(1)

lint = opts.lint
console = opts.console

if opts.pidfile:
    thepidfile = opts.pidfile

if opts.configfile:
    theconfigfile = opts.configfile
    theloggingfile = os.path.join(
        os.path.split(theconfigfile)[0], os.path.split(theloggingfile)[1])
    dconfdir = None

config = configparser.RawConfigParser()
if not os.path.exists(theconfigfile):
    print("""Configfile (%s) not found. Please create it by renaming the .dist file and modifying it to your needs""" % theconfigfile)
    sys.exit(1)
readconfig = config.readfp(open(theconfigfile))
# load conf.d
if dconfdir and os.path.isdir(dconfdir):
    filelist = os.listdir(dconfdir)
    configfiles = [dconfdir + '/' + c for c in filelist if c.endswith('.conf')]
    readfiles = config.read(configfiles)


daemon = DaemonStuff(thepidfile)
# we could have an empty config file
# no daemon for lint&console mode
if not lint and not console and not opts.foreground:
    if config.has_option('main', 'daemonize'):
        if config.getboolean('main', 'daemonize'):
            daemon.createDaemon()
    else:  # option not specified -> default to run daemon
        daemon.createDaemon()


# drop privileges
try:
    running_user = config.get('main', 'user')
    running_group = config.get('main', 'group')
except:
    running_user = 'nobody'
    running_group = 'nobody'

priv_drop_ok = False
try:
    daemon.drop_privs(running_user, running_group)
    priv_drop_ok = True
except:
    err = sys.exc_info()[1]
    print("Could not drop privileges to %s/%s : %s" %
          (running_user, running_group, str(err)))


# set up logging
if lint:
    # define a Handler which writes INFO messages or higher to the sys.stderr
    console = logging.StreamHandler()
    console.setLevel(logging.DEBUG)
    # set a format which is simpler for console use
    formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
    # tell the handler to use this format
    console.setFormatter(formatter)
    # add the handler to the root logger
    logging.getLogger('').addHandler(console)
    fc = fuglu.funkyconsole.FunkyConsole()
    print(fc.strcolor("Fuglu", "yellow"), end=' ')
    print(fc.strcolor(FUGLU_VERSION, "green"))
    print("----------", fc.strcolor("LINT MODE",
                                    (fc.MODE["blink"], fc.FG["magenta"])), "----------")

else:
    logging.config.fileConfig(theloggingfile)

baselogger = logging.getLogger('')
baselogger.info("FuGLU Version %s starting up" % FUGLU_VERSION)

# instantiate the MainController and load default configuration
controller = MainController(config)
controller.propagate_core_defaults()


if lint:
    controller.lint()
    # the controller doesn't know about the logging.conf, so we lint this here
    print("")
    if priv_drop_ok:
        print("Checking logging configuration....")
        try:
            logging.config.fileConfig(theloggingfile)
            logging.info("fuglu --lint log configuration test")
            print(fc.strcolor("OK", "green"))
        except Exception as e:
            print("Logging configuration check failed: %s " % str(e))
            print("This may prevent the daemon from starting up.")
            print(
                "Make sure the log directory exists and is writable by user '%s' " % running_user)
            print(fc.strcolor("NOT OK", "red"))
    else:
        print(fc.strcolor("WARNING:", "yellow"))
        print("Skipping logging configuration check because I could not switch to user '%s' earlier." % running_user)
        print("please re-run fuglu --lint as privileged user")
        print("(problems in the logging configuration could prevent the fuglu daemon from starting up)")

else:
    signal.signal(signal.SIGHUP, sighup)
    if console:
        controller.debugconsole = True
    controller.startup()
