"""Parsing library for the dn42 registry.

All data is parsed as python dictionaries, and can be exported as JSON.
Example usage:

    from registry import Dns
    dns = Dns("/home/example/net.dn42.registry")
    print(dns.data["internal.dn42"])
    with open("/tmp/dns.json", "w") as f:
        dns.write_json(f)

There are several classes available: Inetnum, AutNum, etc (see below).
They follow the naming convention of the folders in data/, using
CamelCase.

There is also a big class containing all relevant data from the registry,
in case you're not afraid of the performance penalty of parsing 1145 small
files:

    from registry import Registry
    dn42 = Registry("/home/example/net.dn42.registry")
    print(dn42.dns.data)
    print(dn42.inetnum.data)

"""

import os
import json

def parse_record(stream):
    """General parsing of the "key: value" syntax. Returns a key -> [values]
    dictionary.
    """
    d = dict()
    for entry in stream.readlines():
        try:
            key, value = [s.strip() for s in entry.split(':', 1)]
            if not key in d:
                d[key] = list()
            d[key].append(value)
        except ValueError: pass
    return d


def parse_records(records_dir, replace_underscore=None):
    """Takes a directory containing records, and builds a dictionary mapping
    the filename of each record to its parsed data.  If requested, we
    transform '_' by [replace_underscore] in the name of the records.

    """
    records = dict()
    for record in os.listdir(records_dir):
        record_path = os.path.join(records_dir, record)
        record_key = record.replace('_', replace_underscore) if replace_underscore else record
        with open(record_path, "r") as f:
            records[record_key] = parse_record(f)
    return records


class Dn42Entry(object):
    """Should not be used directly, use one of the sub-classes below."""
    directory = ""
    data = dict()

    def __init__(self, registrypath, replace_underscore=None):
        fullpath = os.path.join(registrypath, "data", self.directory)
        self.data = parse_records(fullpath, replace_underscore)

    def write_json(self, stream):
        json.dump(self.data, stream)

    def get_json(self):
        return json.dumps(self.data)


class Dns(Dn42Entry):
    def __init__(self, registrypath):
        self.directory = "dns"
        super(Dns, self).__init__(registrypath)


class Inetnum(Dn42Entry):
    def __init__(self, registrypath):
        self.directory = "inetnum"
        super(Inetnum, self).__init__(registrypath, '/')

class Inet6num(Dn42Entry):
    def __init__(self, registrypath):
        self.directory = "inet6num"
        super(Inet6num, self).__init__(registrypath, '/')


class Route(Dn42Entry):
    def __init__(self, registrypath):
        self.directory = "route"
        super(Route, self).__init__(registrypath, '/')

class Route6(Dn42Entry):
    def __init__(self, registrypath):
        self.directory = "route6"
        super(Route6, self).__init__(registrypath, '/')


class Person(Dn42Entry):
    def __init__(self, registrypath):
        self.directory = "person"
        super(Person, self).__init__(registrypath)

class Organisation(Dn42Entry):
    def __init__(self, registrypath):
        self.directory = "organisation"
        super(Organisation, self).__init__(registrypath)

class Mntner(Dn42Entry):
    def __init__(self, registrypath):
        self.directory = "mntner"
        super(Mntner, self).__init__(registrypath)


class AsBlock(Dn42Entry):
    def __init__(self, registrypath):
        self.directory = "as-block"
        super(AsBlock, self).__init__(registrypath, '-')

class AsSet(Dn42Entry):
    def __init__(self, registrypath):
        self.directory = "as-set"
        super(AsSet, self).__init__(registrypath)

class AutNum(Dn42Entry):
    def __init__(self, registrypath):
        self.directory = "aut-num"
        super(AutNum, self).__init__(registrypath)


class Registry(Dn42Entry):
    """Big class that provides all available data from the registry."""
    def __init__(self, registrypath):
        self.dns = Dns(registrypath)
        self.inetnum = Inetnum(registrypath)
        self.inet6num = Inet6num(registrypath)
        self.route = Route(registrypath)
        self.route6 = Route6(registrypath)
        self.person = Person(registrypath)
        self.organisation = Organisation(registrypath)
        self.mntner = Mntner(registrypath)
        self.asblock = AsBlock(registrypath)
        self.asset = AsSet(registrypath)
        self.autnum = AutNum(registrypath)