#!/usr/bin/python
# coding=utf-8
import sys
import os
import logging
import importlib

from gi.repository import Gio, GLib

# support running uninstalled
_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
if 'BLUEMAN_SOURCE' in os.environ:
    sys.path = [_dirname, os.path.join(_dirname, 'module', '.libs')] + sys.path
    timeout = 9999
    os.environ["GSETTINGS_SCHEMA_DIR"] = os.path.join(_dirname, "data")
else:
    timeout = 30

from _blueman import set_probe_debug
from blueman.Constants import POLKIT
from blueman.Functions import set_proc_title, create_logger, create_parser

import blueman.plugins.mechanism
from blueman.plugins.MechanismPlugin import MechanismPlugin

from blueman.main.DbusService import DbusService, DbusError

loop = GLib.MainLoop()


class StreamToLogger(object):
    """
    Fake file-like stream object that redirects writes to a logger instance.
    """
    def __init__(self, logger, log_level=logging.INFO):
        self.logger = logger
        self.log_level = log_level
        self.linebuf = ''

    def write(self, buf):
        for line in buf.rstrip().splitlines():
            self.logger.log(self.log_level, line.rstrip())

    def flush(self):
        pass


parser = create_parser(syslog=False)
parser.add_argument("-d", "--debug", dest="debug", action="store_true")
parser.add_argument("-s", "--stop-timer", dest="stoptimer", action="store_true")
args = parser.parse_args()

if args.LEVEL.upper() == "DEBUG":
    log_level = logging.DEBUG
elif args.LEVEL.upper() == "INFO":
    log_level = logging.INFO
elif args.LEVEL.upper() == "WARNING":
    log_level = logging.WARNING
elif args.LEVEL.upper() == "ERROR":
    log_level = logging.ERROR
elif args.LEVEL.upper() == "CRITICAL":
    log_level = logging.CRITICAL
else:
    log_level = logging.WARNING

logger = create_logger(log_level, "blueman-mechanism", syslog=True)

if args.debug:
    logging.info("Enabled verbose output")
    set_probe_debug(True)

sl = StreamToLogger(logger, logging.INFO)
sys.stdout = sl

sl = StreamToLogger(logger, logging.ERROR)
sys.stderr = sl

logging.info("Starting blueman-mechanism")

os.environ["PATH"] = "/usr/bin:/bin:/usr/sbin:/sbin"

dhcp_pids = []


class Timer:
    def __init__(self):
        self.time = 0
        self.stopped = False
        GLib.timeout_add(1000, self.tick)

    def tick(self):
        if not self.stopped:
            self.time += 1
            if self.time == timeout:
                logging.info("Exiting")
                loop.quit()

        return True

    def reset(self):
        self.time = 0

    def stop(self):
        self.stopped = True

    def resume(self):
        self.stopped = False
        self.reset()


class ConfService(DbusService):
    def __init__(self):
        super().__init__("org.blueman.Mechanism", "org.blueman.Mechanism", "/org/blueman/mechanism", Gio.BusType.SYSTEM)
        self.timer = Timer()
        if args.stoptimer:
            self.timer.stop()

        if POLKIT:
            try:
                self.pk = Gio.DBusProxy.new_for_bus_sync(
                    Gio.BusType.SYSTEM,
                    Gio.DBusProxyFlags.NONE,
                    None,
                    'org.freedesktop.PolicyKit1',
                    '/org/freedesktop/PolicyKit1/Authority',
                    'org.freedesktop.PolicyKit1.Authority')
            except Exception as e:
                logging.exception(e)
                self.pk = None
        else:
            self.pk = None

        path = os.path.dirname(blueman.plugins.mechanism.__file__)
        plugins = []
        for root, dirs, files in os.walk(path):
            for f in files:
                if f.endswith(".py") and not (f.endswith(".pyc") or f.endswith("_.py")):
                    plugins.append(f[0:-3])

        for plugin in plugins:
            try:
                importlib.import_module("blueman.plugins.mechanism.%s" % plugin)
            except ImportError:
                logging.error("Skipping plugin %s" % plugin, exc_info=True)

        classes = MechanismPlugin.__subclasses__()
        for cls in classes:
            logging.info("loading %s" % cls.__name__)
            cls(self)

        self.register()

    def confirm_authorization(self, subject, action_id):
        self.timer.reset()
        if not POLKIT:
            return
        else:
            if not self.pk:
                raise DbusError("Blueman was built with PolicyKit-1 support, but it's not available on the system")

        v_subject = GLib.Variant('s', subject)
        res = self.pk.CheckAuthorization('((sa{sv})sa{ss}us)', ("system-bus-name", {"name": v_subject}),
                                         action_id, {}, 1, "")

        logging.debug(str(res))
        (is_authorized, is_challenge, details) = res
        if not is_authorized:
            raise DbusError("Not authorized")


set_proc_title()
ConfService()
loop.run()
