import pdns.remotebackend
import sys
import io
import time


# define a simple $domain

ID_DOMAIN = {
    1: 'unit.test.',
}

DOMAINS = {
    'unit.test.': {
        'id': 1,
        'ttl': 300,
        'name': 'unit.test.',
        'notified_serial': 0,
        'meta': {},
        'keys': {},
        'rr': {
            'unit.test.' : {
                'SOA': ["ns.unit.test. hostmaster.unit.test. 1 2 3 4 5"],
                'NS':  ["ns1.unit.test.", "ns2.unit.test."],
            },
            'ns1.unit.test.': {
               'A': ["10.0.0.1"]
            },
            'ns2.unit.test.': {
               'A': ["10.0.0.2"]
            },
            'empty.unit.test.': {}
        },
        'kind': 'native',
    },
    'master.test.': {
        'id': 2,
        'ttl': 300,
        'name': 'master.test.',
        'notified_serial': 2,
        'meta': {},
        'keys': {},
        'rr': {
            'master.test.': {
                'SOA': ["ns.master.test. hostmaster.master.test. 1 2 3 4 5"],
            }
        },
        'kind': 'master',
    },
}

TSIG_KEYS = {
    'test.': {
        'name': 'test.',
        'algorithm': 'NULL.',
        'content': 'NULL',
    }
}

MASTERS = {
    'ns1.unit.test.': {
        'ip': '10.0.0.1'
    }
}

class Handler(pdns.remotebackend.Handler):
    def get_domain(self, domain):
        if not domain.endswith("."):
            domain = domain + "."
        while len(domain) > 0:
            if domain in DOMAINS:
                return DOMAINS[domain]
            p = domain.find(".")
            if p == -1:
                break
            domain = domain[p+1:]
        return None

    def do_lookup(self, qname='', qtype='', **kwargs):
        domain = self.get_domain(qname)
        if domain:
            self.result = []
            rrset = domain['rr'].get(qname, {'qtype': []})
            rr = rrset.get(qtype, [])
            for r in rr:
                self.result.append(self.record(qname=qname, qtype=qtype, content=r, ttl=domain['ttl']))

    def do_list(self, zonename="", **kwargs):
        domain = self.get_domain(zonename)
        if domain:
            self.result = []
            for qname, rrset in domain['rr'].items():
                for qtype, rr in rrset.items():
                    for r in rr:
                        self.result.append(self.record(qname=qname, qtype=qtype, content=r, ttl=domain['ttl']))

    def do_getalldomainmetadata(self, name='', **kwargs):
        domain = self.get_domain(name)
        if domain:
            self.result = domain['meta']

    def do_getdomainmetadata(self, name='', kind='', **kwargs):
        self.do_getalldomainmetadata(name=name)
        if self.result:
            self.result = self.result[kind]

    def do_setdomainmetadata(self, name='', kind='', value=None, **kwargs):
        domain = self.get_domain(name)
        if domain:
            if value is None:
                del domain['meta'][kind]
            else:
                domain['meta'][kind] = value
            self.result = True

    def do_adddomainkey(self, name='', key={}, **kwargs):
        domain = self.get_domain(name)
        if domain:
            k_id = len(domain['keys']) + 1
            key['id'] = k_id
            domain['keys'][k_id] = key
            self.result = k_id

    def do_getdomainkeys(self, name='', **kwargs):
        domain = self.get_domain(name)
        if domain:
            self.result = []
            for k_id, k in domain['keys'].items():
                self.result.append(k)

    def do_activatedomainkey(self, name='', **kwargs):
        domain = self.get_domain(name)
        if domain:
            key = domain['keys'].get(int(kwargs['id']))
            if key:
                key['active'] = True
                self.result = True

    def do_deactivatedomainkey(self, name='', **kwargs):
        domain = self.get_domain(name)
        if domain:
            key = domain['keys'].get(int(kwargs['id']))
            if key:
                key['active'] = False
                self.result = True

    def do_publishdomainkey(self, name='', **kwargs):
        domain = self.get_domain(name)
        if domain:
            key = domain['keys'].get(int(kwargs['id']))
            if key:
                key['published'] = True
                self.result = True

    def do_unpublishdomainkey(self, name='', **kwargs):
        domain = self.get_domain(name)
        if domain:
            key = domain['keys'].get(int(kwargs['id']))
            if key:
                key['published'] = False
                self.result = True

    def do_removedomainkey(self, name='', **kwargs):
        domain = self.get_domain(name)
        if domain:
            k_id = int(kwargs['id'])
            if k_id in domain['keys']:
                del domain['keys'][k_id]
                self.result = True

    def do_getbeforeandafternamesabsolute(self, qname='', **kwargs):
        if qname == 'middle.unit.test.':
            self.result = {
                'unhashed': 'middle.',
                'before': 'begin.',
                'after': 'stop.',
            }

    def do_setnotified(self, **kwargs):
        d_id = int(kwargs['id'])
        domain_name = ID_DOMAIN.get(d_id)
        domain = DOMAINS.get(domain_name)
        if domain:
            domain['notified_serial'] = kwargs['serial']
            self.result = True

    def fill_domaininfo(self, name=""):
        domain = self.get_domain(name)
        if domain:
            self.result.append({
                'id': domain['id'],
                'zone': domain['name'],
                'masters': MASTERS,
                'notified_serial': domain['notified_serial'],
                'serial': domain['notified_serial'],
                'last_check': int(time.time()),
                'kind': domain['kind']
            })

    def do_getdomaininfo(self, name="", **kwargs):
        self.result = []
        self.fill_domaininfo(name)
        if self.result:
            self.result = self.result[0]

    def do_ismaster(self, name='', ip='', **kwargs):
        ips = MASTERS.get(name, [])
        if ip in ips:
            self.result = True

    def do_supermasterbackend(self, domain='', nsset=[], **kwargs):
        d_id = len(DOMAINS) + 1
        dom = domain.lower()
        domain = {
            'id': d_id,
            'name': dom,
            'kind': 'slave',
            'notified_serial': 0,
            'meta': {},
            'keys': {},
            'rr': {
                dom: {
                    'SOA': ["ns.%s hostmaster.%s 1 2 3 4 5" % (dom, dom)],
                }
            },
            'ttl': 300,
        }

        nsset = []
        for rr in nsset:
            nsset.append(self.record(qname=rr['qname'], qtype=rr['qtype'], content=rr['content'], ttl=rr['ttl']))

        domain['rr'][dom]['NS'] = nsset
        DOMAINS[dom] = domain

        self.result = [{
            'nameserver': 'ns.%s' % dom,
            'account': ''
        }]


    def do_createslavedomain(self, domain='', **kwargs):
        d_id = len(DOMAINS) + 1
        dom = domain.lower()
        domain = {
            'id': d_id,
            'name': dom,
            'kind': 'slave',
            'notified_serial': 0,
            'ttl': 300,
            'meta': {},
            'keys': {},
            'rr': {
            }
        }
        self.result = True

    def do_feedrecord(self, rr={}, **kwargs):
        qname = rr['qname']
        qtype = rr['qtype']
        domain = self.get_domain(qname)
        if domain:
            if not qname in domain['rr']:
                domain['rr'][qname] = {qtype: []}
            elif not qtype in domain['rr'][qname]:
                 domain['rr'][qname][qtype] = []
            domain['rr'][qname][qtype].append(self.record(
                qname=qname,
                qtype=qtype,
                content=rr['content'],
                ttl=rr.get('ttl', domain['ttl']))
            )
            self.result = True

    def do_replacerrset(self, qname='', qtype='', rrset=[], **kwargs):
        domain = self.get_domain(qname)
        if domain and qname in domain['rr']:
            if qtype in domain['rr'][qname]:
                del domain['rr'][qname][qtype]
        for row in rrset:
            self.do_feedrecord(rr=row)

    def do_feedents(self, **kwargs):
        self.result = True

    def do_feedents3(self, **kwargs):
        self.result = True

    def do_gettsigkey(self, name='', **kwargs):
        if name in TSIG_KEYS:
            self.result = TSIG_KEYS[name]

    def do_settsigkey(self, name='', algorithm='', content='', **kwargs):
        TSIG_KEYS[name] = {
            'name': name,
            'algorithm': algorithm,
            'content': content,
        }
        self.result = True

    def do_gettsigkeys(self, **kwargs):
        self.result = []
        for name, key in TSIG_KEYS.items():
            self.result.append(key)

    def do_deletetsigkey(self, name='', **kwargs):
        if name in TSIG_KEYS:
            del TSIG_KEYS[name]
            self.result = True

    def do_starttransaction(self, **kwargs):
        self.result = True

    def do_committransaction(self, **kwargs):
        self.result = True

    def do_aborttransaction(self, **kwargs):
        self.result = True

    def do_directbackendcmd(self, query='', **kwargs):
        self.result = query

    def do_getalldomains(self, **kwargs):
        self.result = []
        for name in DOMAINS.keys():
            self.fill_domaininfo(name=name)

    def do_getupdatedmasters(self, **kwargs):
        self.result = []
        for name in DOMAINS.keys():
            if DOMAINS[name]['kind'] == 'master':
                self.fill_domaininfo(name=name)
