#! /usr/bin/env python
import locale
import os
import sys
import time

import avahi
import dbus
from encodings.idna import ToASCII

import logging.handlers


class Settings:
    # Got these from /usr/include/avahi-common/defs.h
    TTL = 60
    CLASS_IN = 0x01
    TYPE_CNAME = 0x05

    ALIASES_CONFIG = "/etc/avahi/aliases"
    ALIAS_CONF_PATH = "/etc/avahi/aliases.d"
    ALIAS_DEFINITIONS = [os.path.join(ALIAS_CONF_PATH, config_file) for config_file in os.listdir(ALIAS_CONF_PATH)]


class AvahiAliases:
    fqdn = None
    bus = None
    group = None
    server = None
    aliases = None
    logger = None
    detach_process = True
    stdin_path = '/dev/null'
    stdout_path = '/dev/null'
    stderr_path = '/dev/null'
    pidfile_path = '/var/run/avahi-aliases.pid'
    pidfile_timeout = 5

    def __init__(self, *args, **kwargs):

        # setup logging
        self.logger = logging.getLogger(os.path.basename(__file__))
        self.logger.setLevel(logging.DEBUG)
        # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        # self.logger.setFormatter(formatter)
        handler = logging.handlers.SysLogHandler(address='/dev/log')
        self.logger.addHandler(handler)

    def get_aliases(self, path=None):
        """ Steps through all config alias files and builds a set of aliases """
        aliases = set()
        for config_file_path in path:
            config_file = open(config_file_path, 'r')
            for line in config_file:
                entry = line.strip('\n')
                if len(entry) > 0 and not entry.startswith("#"):
                    aliases.add(entry)
            config_file.close()

        return aliases

    def publish(self, cname):
        """ Push the cname into the avahi stack
            copied from https://gist.github.com/gdamjan/3168336
        """
        bus = dbus.SystemBus()
        server = dbus.Interface(
            bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER),
            avahi.DBUS_INTERFACE_SERVER
        )
        group = dbus.Interface(
            bus.get_object(avahi.DBUS_NAME, server.EntryGroupNew()),
            avahi.DBUS_INTERFACE_ENTRY_GROUP
        )

        cname = self.encode(cname)
        rdata = self.encode_rdata(server.GetHostNameFqdn())
        rdata = avahi.string_to_byte_array(rdata)

        group.AddRecord(
            avahi.IF_UNSPEC,
            avahi.PROTO_UNSPEC,
            dbus.UInt32(0),
            cname,
            Settings.CLASS_IN,
            Settings.TYPE_CNAME,
            Settings.TTL,
            rdata
        )
        group.Commit()

    def encode(self, name):
        """ convert the string to ascii
            copied from https://gist.github.com/gdamjan/3168336
        """
        return '.'.join(ToASCII(p) for p in name.split('.') if p)

    def encode_rdata(self, name):
        """
            copied from https://gist.github.com/gdamjan/3168336
        """
        def enc(part):
            a = ToASCII(part)
            return chr(len(a)), a
        return ''.join('%s%s' % enc(p) for p in name.split('.') if p) + '\0'

    def run(self, *args, **kwargs):
        """ runner for python-daemon """
        self.aliases = self.get_aliases(Settings.ALIAS_DEFINITIONS)

        for cname in self.aliases:
            cname = unicode(cname, locale.getpreferredencoding())
            self.logger.info("Announcing: {}".format(cname))
            print("Announcing", cname)
            self.publish(cname)

        self.logger.info("Announced all aliases")

        while True:
            time.sleep(Settings.TTL)
        self.logger.info("Stopping")
        sys.exit(0)

if __name__ == "__main__":
    aliases_object = AvahiAliases()
    aliases_object.run()
