#!/usr/bin/env python3

# Copyright © 2012-2022 Jakub Wilk <jwilk@jwilk.net>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the “Software”), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import datetime
import functools
import os
import subprocess as ipc
import sys
import json

int(0_0)  # Python >= 3.6 is required

class Panic(ValueError):
    pass

@functools.lru_cache()
def get_iso_codes_version():
    version = ipc.check_output(['pkg-config', 'iso-codes', '--modversion'])
    version = version.decode('ASCII').strip()
    return version

@functools.lru_cache()
def get_iso_codes_dir():
    prefix = ipc.check_output(['pkg-config', 'iso-codes', '--variable=prefix'])
    prefix = prefix.decode('ASCII').strip()
    return f'{prefix}/share/iso-codes/json'

def main():
    basedir = os.path.join(
        os.path.dirname(__file__),
        os.pardir,
    )
    path = os.path.join(basedir, 'data', 'iso-codes')
    sys.stdout = open(path + '.tmp', 'wt', encoding='UTF-8')  # pylint: disable=consider-using-with
    iso_codes_version = get_iso_codes_version()
    today = datetime.date.today()
    print(f'''\
# This file has been generated automatically by private/update-iso-codes.
# Do not edit.
# iso-codes version: {iso_codes_version}
# Last update: {today}
''')
    generate_iso_639()
    generate_iso_3166()
    sys.stdout.close()
    os.rename(path + '.tmp', path)

def load_json(path):
    with open(path, 'rt', encoding='UTF-8') as file:
        return json.load(file)

def generate_iso_639():
    # =======================
    # ISO 639: language codes
    # =======================
    l2t_to_2b = {}
    iso_639 = {}
    data = load_json(get_iso_codes_dir() + '/iso_639-2.json')
    for item in data['639-2']:
        l2t = item['alpha_3']
        l2b = item.get('bibliographic', l2t)
        if l2b == l2t == 'qaa-qtz':
            continue
        for l in l2b, l2t:
            if len(l) != 3:
                raise Panic(f'len({l!r}) != 3')
        if l2b != l2t:
            l2t_to_2b[l2t] = l2b
    iso_639 = {}
    data = load_json(get_iso_codes_dir() + '/iso_639-3.json')
    for item in data['639-3']:
        code = item['alpha_3']
        if len(code) != 3:
            raise Panic(f'len({code!r}) != 3')
        code1 = item.get('alpha_2')
        code2 = item.get('terminology')
        if code2 is None:
            # We're not interested in languages that are not in 639-2 (yet?).
            continue
        if code2 != code:
            raise Panic(f'{code!r} != {code2!r}')
        scope = item['scope']
        if scope == 'S':
            # Not a real language, ignore.
            continue
        elif scope in {'M', 'I'}:
            pass
        else:
            raise Panic(f'unknown scope: {scope!r}')
        reference_name = item['name']
        if reference_name in iso_639:
            raise Panic(f'duplicate reference name: {reference_name!r}')
        if code1 is not None:
            if len(code1) == 2:
                codelist = [code1, code]
            else:
                raise Panic(f'len({code1!r}) != 2')
        else:
            codelist = [code]
        try:
            codelist += [l2t_to_2b[code]]
        except KeyError:
            pass
        iso_639[reference_name] = codelist
    print('[language-codes]')
    iso_639_rev = {}
    for code, *aliases in iso_639.values():
        for alias in aliases:
            iso_639_rev[alias] = code
        if not aliases:
            iso_639_rev[code] = ''
    for alias, code in sorted(iso_639_rev.items()):
        print(f'{alias} = {code}'.rstrip())
    print()

def generate_iso_3166():
    # =========================
    # ISO 3166: territory codes
    # =========================
    iso_3166 = set()
    data = load_json(get_iso_codes_dir() + '/iso_3166-1.json')
    for item in data['3166-1']:
        cc = item['alpha_2']
        iso_3166.add(cc)
    print('[territory-codes]')
    for cc in sorted(iso_3166):
        print(f'{cc} =')
    print()
    print('# vim\72ft=dosini')

if __name__ == '__main__':
    main()

# vim:ts=4 sts=4 sw=4 et
