#!/usr/pkg/bin/python3.12

'''
Copyright 2022 Veloman Yunkan <veloman.yunkan@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or any
later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
'''

import argparse
import os.path
import re
import json

def to_identifier(name):
    ident = re.sub(r'[^0-9a-zA-Z]', '_', name)
    if ident[0].isnumeric():
        return "_"+ident
    return ident

def lang_code(filename):
    filename = os.path.basename(filename)
    lang = to_identifier(os.path.splitext(filename)[0])
    print(filename, '->', lang)
    return lang

from string import Template

def expand_cxx_template(t, **kwargs):
    return Template(t).substitute(**kwargs)

def cxx_string_literal(s):
    # Taking advantage of the fact the JSON string escape rules match
    # those of C++
    return 'u8' + json.dumps(s)

string_table_cxx_template = '''
const I18nString $TABLE_NAME[] = {
  $TABLE_ENTRIES
};
'''

lang_table_entry_cxx_template = '''
    {
        $LANG_STRING_LITERAL,
        ARRAY_ELEMENT_COUNT($STRING_TABLE_NAME),
        $STRING_TABLE_NAME
    }'''

cxxfile_template = '''// This file is automatically generated. Do not modify it.

#include "server/i18n_utils.h"

namespace kiwix {
namespace i18n {

namespace
{

$STRING_DATA

} // unnamed namespace

#define ARRAY_ELEMENT_COUNT(a) (sizeof(a)/sizeof(a[0]))

extern const I18nStringTable stringTables[] = {
  $LANG_TABLE
};

extern const size_t langCount = $LANG_COUNT;

} // namespace i18n
} // namespace kiwix
'''

class Resource:
    def __init__(self, filename):
        filename = filename.strip()
        self.filename = filename
        self.lang_code = lang_code(filename)
        with open(filename, 'r', encoding='utf-8') as f:
            self.data = f.read()

    def get_string_table_name(self):
        return "string_table_for_" + self.lang_code

    def get_string_table(self):
        table_entries = ",\n  ".join(self.get_string_table_entries())
        return expand_cxx_template(string_table_cxx_template,
                    TABLE_NAME=self.get_string_table_name(),
                    TABLE_ENTRIES=table_entries)

    def get_string_table_entries(self):
        d = json.loads(self.data)
        for k in sorted(d.keys()):
            if k != "@metadata":
                key_string = cxx_string_literal(k)
                value_string = cxx_string_literal(d[k])
                yield '{ ' + key_string + ', ' + value_string + ' }'

    def get_lang_table_entry(self):
        return expand_cxx_template(lang_table_entry_cxx_template,
                LANG_STRING_LITERAL=cxx_string_literal(self.lang_code),
                STRING_TABLE_NAME=self.get_string_table_name())



def gen_c_file(resources):
    string_data = []
    lang_table = []
    for r in resources:
        string_data.append(r.get_string_table())
        lang_table.append(r.get_lang_table_entry())

    return expand_cxx_template(cxxfile_template,
                STRING_DATA="\n".join(string_data),
                LANG_TABLE=",\n  ".join(lang_table),
                LANG_COUNT=len(resources)
           )



if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--cxxfile',
                        required=True,
                        help='The Cpp file name to generate')
    parser.add_argument('i18n_resource_files', nargs='+',
                        help='The list of resources to compile.')
    args = parser.parse_args()

    resources = [Resource(filename) for filename in args.i18n_resource_files]

    with open(args.cxxfile, 'w') as f:
        f.write(gen_c_file(resources))

