#!/usr/bin/python3
#
# Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#

# This script generates the collation headers, given a dump of the SHOW COLLATION
# statement for MySQL and MariaDB. MySQL 5 and 8 are compatible, while MariaDB
# renamed some collations in a way that makes having them in a separate header preferable.
# e.g. mysql -u root -e "SHOW COLLATION" > private/mysql-collations.txt
#      mysql -u root -e "SHOW COLLATION" > private/mariadb-collations.txt

import pandas as pd
from pathlib import Path
from os import path
from typing import Literal
from subprocess import run

REPO_BASE = Path(path.abspath(path.join(path.dirname(path.realpath(__file__)), '..', '..')))
MYSQL_SHOW_COLLATION = REPO_BASE.joinpath('private', 'mysql-collations.txt')
MARIADB_SHOW_COLLATION = REPO_BASE.joinpath('private', 'mariadb-collations.txt')

COLLATIONS_ENTRY_TEMPLATE = '''
// Identifies the {collation} collation in {flavor} servers.
constexpr std::uint16_t {collation} = {id};
'''

COLLATIONS_HEADER_TEMPLATE = '''
#ifndef BOOST_MYSQL_{flavor}_COLLATION_IDS_HPP
#define BOOST_MYSQL_{flavor}_COLLATION_IDS_HPP

// This header was generated by collations.py - do not edit directly

#include <cstdint>

namespace boost {{
namespace mysql {{
namespace {flavor}_collations {{
{entries}
}}  // namespace {flavor}_collations
}}  // namespace mysql
}}  // namespace boost

#endif
'''

def parse_show_collation(fname: Path) -> pd.DataFrame:
    return pd \
        .read_table(fname)[['Collation', 'Id']] \
        .rename(columns={ 'Collation': 'collation', 'Id': 'id'}) \
        .sort_values(by='id')


def render_collations_header(flavor: Literal['mysql', 'mariadb'], df_collations: pd.DataFrame) -> str:
    entries = ''.join(COLLATIONS_ENTRY_TEMPLATE.format(
        collation=r.collation,
        id=r.id,
        flavor=flavor
    ) for r in df_collations.itertuples())
    return COLLATIONS_HEADER_TEMPLATE.format(flavor=flavor, entries=entries)


# Actually perform the generation
def write_headers(df_mysql: pd.DataFrame, df_mariadb: pd.DataFrame) -> None:
    for flavor, df in [('mysql', df_mysql), ('mariadb', df_mariadb)]:
        fname = REPO_BASE.joinpath('include', 'boost', 'mysql', f'{flavor}_collations.hpp')
        with open(fname, 'wt') as f:
            f.write(render_collations_header(flavor, df))


# We need to run file_headers.py to set copyrights and headers
def invoke_file_headers() -> None:
    run(['python', str(REPO_BASE.joinpath('tools', 'scripts', 'file_headers.py'))])


def main():
    df_mysql = parse_show_collation(MYSQL_SHOW_COLLATION)
    df_mariadb = parse_show_collation(MARIADB_SHOW_COLLATION)
    write_headers(df_mysql, df_mariadb)
    invoke_file_headers()


if __name__ == '__main__':
    main()
