#!/usr/bin/python3

import apt
import csv
import os
import tempfile
from urllib.request import urlretrieve

url = 'https://raw.githubusercontent.com/coq/platform/refs/heads/main/doc/PackageTable~8.19~2024.10.csv?plain=1'

cache = apt.Cache()
cache.open()

def exclude_package(name):
    if name.startswith('conf-'):
        return True
    if name.startswith('base-'):
        return True
    if name.startswith('host-'):
        return True
    if name in ['ocaml-config', 'ocaml-option-flambda', 'seq']:
        return True
    return False

def debian_version(debname):
    try:
        return cache[debname].versions[0].version
    except:
        return ''

def debian_name(name):
    mapping = {
        'atd': 'libatd-ocaml',
        'atdgen': 'libatdgen-ocaml',
        'atdgen-runtime': 'libatdgen-ocaml',
        'atdts': 'atdts',
        'base': 'libbase-ocaml',
        'biniou': 'libbiniou-ocaml',
        'cairo2': 'libcairo2-ocaml',
        'camlp-streams': 'libcamlp-streams-ocaml',
        'cmdliner': 'libcmdliner-ocaml-dev',
        'coq': 'coq',
        'coq-aac-tactics': 'libcoq-aac-tactics',
        'coq-bignums': 'libcoq-bignums',
        'coq-coqeal': 'libcoq-coqeal',
        'coq-coqprime': 'libcoq-coqprime',
        'coq-coqprime-generator': 'libcoq-coqprime',
        'coq-coquelicot': 'libcoq-coquelicot',
        'coq-core': 'libcoq-core-ocaml',
        'coq-corn': 'libcoq-corn',
        'coq-dpdgraph': 'libcoq-dpdgraph',
        'coq-deriving': 'libcoq-deriving',
        'coq-elpi': 'libcoq-elpi',
        'coq-equations': 'libcoq-equations',
        'coq-ext-lib': 'libcoq-ext-lib',
        'coq-extructures': 'libcoq-extructures',
        'coq-flocq': 'libcoq-flocq',
        'coq-gappa': 'libcoq-gappa',
        'coq-hammer': 'libcoq-hammer',
        'coq-hammer-tactics': 'libcoq-hammer',
        'coq-hierarchy-builder': 'libcoq-hierarchy-builder',
        'coq-hott': 'libcoq-hott',
        'coqide': 'coqide',
        'coqide-server': 'coq',
        'coq-interval': 'libcoq-interval',
        'coq-iris': 'libcoq-iris',
        'coq-iris-heap-lang': 'libcoq-iris',
        'coq-libhyps': 'libcoq-libhyps',
        'coq-math-classes': 'libcoq-math-classes',
        'coq-mathcomp-algebra': 'libcoq-mathcomp-algebra',
        'coq-mathcomp-algebra-tactics': 'libcoq-mathcomp-algebra-tactics',
        'coq-mathcomp-analysis': 'libcoq-mathcomp-analysis',
        'coq-mathcomp-bigenough': 'libcoq-mathcomp-bigenough',
        'coq-mathcomp-character': 'libcoq-mathcomp-character',
        'coq-mathcomp-classical': 'libcoq-mathcomp-classical',
        'coq-mathcomp-field': 'libcoq-mathcomp-field',
        'coq-mathcomp-fingroup': 'libcoq-mathcomp-fingroup',
        'coq-mathcomp-finmap': 'libcoq-mathcomp-finmap',
        'coq-mathcomp-real-closed': 'libcoq-mathcomp-real-closed',
        'coq-mathcomp-solvable': 'libcoq-mathcomp-solvable',
        'coq-mathcomp-ssreflect': 'libcoq-mathcomp-ssreflect',
        'coq-mathcomp-zify': 'libcoq-mathcomp-zify',
        'coq-mathcomp-multinomials': 'libcoq-mathcomp-multinomials',
        'coq-menhirlib': 'libcoq-menhirlib',
        'coq-metacoq': 'libcoq-metacoq',
        'coq-metacoq-common': 'libcoq-metacoq',
        'coq-metacoq-erasure': 'libcoq-metacoq',
        'coq-metacoq-erasure-plugin': 'libcoq-metacoq',
        'coq-metacoq-pcuic': 'libcoq-metacoq',
        'coq-metacoq-quotation': 'libcoq-metacoq',
        'coq-metacoq-safechecker': 'libcoq-metacoq',
        'coq-metacoq-safechecker-plugin': 'libcoq-metacoq',
        'coq-metacoq-template': 'libcoq-metacoq',
        'coq-metacoq-template-pcuic': 'libcoq-metacoq',
        'coq-metacoq-translations': 'libcoq-metacoq',
        'coq-metacoq-utils': 'libcoq-metacoq',
        'coq-mtac2': 'libcoq-mtac2',
        'coq-ott': 'libcoq-ott',
        'coq-paramcoq': 'libcoq-paramcoq',
        'coq-quickchick': 'libcoq-quickchick',
        'coq-record-update': 'libcoq-record-update',
        'coq-reduction-effects': 'libcoq-reduction-effects',
        'coq-reglang': 'libcoq-reglang',
        'coq-relation-algebra': 'libcoq-relation-algebra',
        'coq-serapi': 'libcoq-serapi-ocaml',
        'coq-simple-io': 'libcoq-simple-io',
        'coq-stdlib': 'libcoq-stdlib',
        'coq-stdpp': 'libcoq-stdpp',
        'coq-unicoq': 'libcoq-unicoq',
        'coq-unimath': 'libcoq-unimath',
        'cppo': 'cppo',
        'csexp': 'libcsexp-ocaml',
        'dune': 'ocaml-dune',
        'dune-configurator': 'ocaml-dune',
        'easy-format': 'libeasy-format-ocaml',
        'elpi': 'elpi',
        'eprover': 'eprover',
        'gappa': 'gappa',
        'gmp-ecm': 'gmp-ecm',
        'lablgtk3': 'liblablgtk3-ocaml',
        'lablgtk3-sourceview3': 'liblablgtksourceview3-ocaml',
        'menhir': 'libmenhir-ocaml-dev',
        'menhirCST': 'libmenhir-ocaml-dev',
        'menhirLib': 'libmenhir-ocaml-dev',
        'menhirSdk': 'libmenhir-ocaml-dev',
        'num': 'libnum-ocaml',
        'ocaml': 'ocaml',
        'ocamlbuild': 'ocamlbuild',
        'ocaml-compiler-libs': 'ocaml-compiler-libs',
        'ocamlfind': 'ocaml-findlib',
        'ocamlgraph': 'libocamlgraph-ocaml-dev',
        'ocaml-variants': 'libvariantslib-ocaml',
        'ott': 'libcoq-ott',
        'parsexp': 'libparsexp-ocaml',
        'ppx_compare': 'libppx-compare-ocaml',
        'ppx_derivers': 'libppx-derivers-ocaml-dev',
        'ppx_deriving': 'libppx-deriving-ocaml',
        'ppx_deriving_yojson': 'libppx-deriving-yojson-ocaml-dev',
        'ppx_hash': 'libppx-hash-ocaml',
        'ppx_import': 'libppx-import-ocaml',
        'ppx_sexp_conv': 'libppx-sexp-conv-ocaml',
        'ppxlib': 'libppxlib-jane-ocaml',
        're': 'libre-ocaml-dev',
        'result': 'libresult-ocaml',
        'sexplib': 'libsexplib-ocaml',
        'sexplib0': 'libsexplib0-ocaml',
        'stdlib-shims': 'libstdlib-ocaml',
        'yojson': 'libyojson-ocaml',
        'zarith': 'libzarith-ocaml-dev',
        'z3': 'z3',
    }
    return mapping.get(name, '')

def parse_coq_platform ():
    result = {}
    with tempfile.NamedTemporaryFile(delete=False, mode='w') as temp_file:
        try:
            urlretrieve(url, temp_file.name)
            with open(temp_file.name) as file:
                reader = csv.reader(file, delimiter=',')
                next(reader) # eat the first line!
                for line in reader:
                    if not exclude_package(line[0]):
                        result[line[0]] = line[1]
        finally:
            if os.path.exists(temp_file.name):
                os.remove(temp_file.name)
    return result

def build_comparison ():
    result = []
    for name, version in parse_coq_platform().items():
        debname = debian_name(name)
        debversion = debian_version(debname)
        result.append((name, version, debname, debversion))
    result.sort()
    return result

def create_document():
    print('<!DOCTYPE html>')
    print('<html>')
    print('<head>')
    print('<title>Coq platform - Debian</title>')
    print('<style>')
    print('table, th, td { border: 1px solid black; }')
    print('table { margin-left:auto; margin-right:auto;}')
    print('</style>')
    print('</head>')
    print('<body>')
    print('<h1 style="text-align:center">Coq platform - Debian</h1>')
    print('<table>')
    print('<tr>')
    print('<th><b>Coq platform name</b></th>')
    print('<th><b>Coq platform version</b></th>')
    print('<th><b>Debian name</b></th>')
    print('<th><b>Debian version</b></th>')
    print('</tr>')
    for name, version, debname, debversion in build_comparison ():
        print('<tr>')
        print(f'<th>{name}</th>')
        print(f'<th>{version}</th>')
        print(f'<th><a href="https://tracker.debian.org/{debname}">{debname}</a></th>')
        print(f'<th>{debversion}</th>')
        print('</tr>')
    print('</table>')
    print('(using <a href="{url}">source</a>)')
    print('</body>')
    print('</html>')


if __name__ == '__main__':
    create_document()
