#!/usr/bin/env python3

import json
import hashlib

# https://pypi.org/project/public-suffix-list/ (package python3-publicsuffix with Debian is not the same)
import public_suffix_list

FILENAME = "result.json"

# Produces an unique identifier for a set of nameservers, after
# canonicalisation.
def set_of(nameservers):
    sorted_list = ";".join(sorted(nameservers, key=lambda s: s.lower()))
    return {"name": sorted_list, "id": hashlib.md5(sorted_list.encode()).hexdigest()}

def total_of_top(sorted_sets, sets, index=None, percentage=10):
    if percentage < 0 or percentage >= 100:
        raise Exception("Absurd percentage %i" % percentage)
    max = int(len(sorted_sets)/percentage)
    top = sorted_sets[0:max]
    total = 0
    for id in top:
        if index is None:
            total += sets[id]
        else:
            total += sets[id]["total"]
    return total

public_suffix_list.setup()
results = json.load(open(FILENAME))
instances = results["instances"]
if len(instances) != results["total"]:
    raise Exception("Inconsistent file %s" % FILENAME)
domains = {}
nameservers = {}
nameserver_domains = {}
nameserver_sets = {}
for instance in instances:
    if instances[instance] is None:
        continue
    domain = instances[instance]["name"]
    if domain in domains:
        domains[domain] += 1
    else:
        domains[domain] = 1
    instance_nameservers = instances[instance]["nameservers"]
    list_domains = []
    for ns in instance_nameservers:
        if ns in nameservers:
            nameservers[ns] += 1
        else:
            nameservers[ns] = 1
        ns_domain = public_suffix_list.registered_domain_name(ns)
        if ns.endswith("linode.com."): # linode.com is not mentioned
                                       # as a public suffix in the PSL
                                       # but the Python package still
                                       # thinks that every nameserver
                                       # is a registered domain.
            ns_domain = "linode.com."
        if ns_domain not in list_domains:
            list_domains.append(ns_domain)
    for domain in list_domains:
        if domain in nameserver_domains:
            nameserver_domains[domain] += 1
        else:
            nameserver_domains[domain] = 1
    set = set_of(instance_nameservers)
    if set["id"] in nameserver_sets:
        nameserver_sets[set["id"]]["total"] += 1
    else:
        nameserver_sets[set["id"]] = set
        nameserver_sets[set["id"]]["total"] = 1
sorted_domains = sorted(domains.keys(), key=lambda s: domains[s], reverse=True)
sorted_nameservers = sorted(nameservers.keys(), key=lambda s: nameservers[s],
                            reverse=True)
sorted_nameserver_domains = sorted(nameserver_domains.keys(), key=lambda s: nameserver_domains[s],
                            reverse=True)
sorted_nameserver_sets = sorted(nameserver_sets.keys(), key=lambda s: nameserver_sets[s]["total"],
                            reverse=True)
print("There are %i instances in %i zones. The largest zone, %s, encompasses %i instances" % \
      (len(instances), len(domains), sorted_domains[0], domains[sorted_domains[0]]))
print("There are %i nameservers. The largest one, %s, hosts %i instances." % \
      (len(nameservers), sorted_nameservers[0], nameservers[sorted_nameservers[0]]))
print("There are %i nameserver sets. The largest one, %s, hosts %i instances. The top 10 %% hosts %i instances." % \
      (len(nameserver_sets), nameserver_sets[sorted_nameserver_sets[0]]["name"], nameserver_sets[sorted_nameserver_sets[0]]["total"], total_of_top(sorted_nameserver_sets, nameserver_sets, "total")))
# Because Cloudflare has many different sets, sorted_nameserver_sets
# underestimates their role.
print("There are %i nameserver's domains. The largest one, %s, hosts %i instances. The top 10 %% hosts %i instances" % (len(nameserver_domains), sorted_nameserver_domains[0], nameserver_domains[sorted_nameserver_domains[0]], total_of_top(sorted_nameserver_domains, nameserver_domains)))

#for set in sorted_nameserver_sets:
#    print(nameserver_sets[set])
#for d in sorted_nameserver_domains:
#    print("%s: %i"% (d, nameserver_domains[d]))
