//=============================================================================
// RPG Maker MZ - TextResource
//
// Copyright 2024 Panzer-IV. All rights reserved.
// This source code or any portion thereof must not be
// reproduced or used without licensed in any manner whatsoever.
//=============================================================================
/*:
 * @target MZ
 * @plugindesc テキストのラベルロード
 * @author 四号戦車
 * @base PluginUtils
 * @base PluginCommonBase
 * @orderAfter PluginCommonBase
 * @orderAfter PluginUtils
 *
 * @help TextResource.js
 *
 * Version: 0.0.2
 *
 * 各プラグインでテキストをラベルと言語設定から読み込むためのプラグインです。
 *
 * @param baseLanguage
 * @text 基礎言語
 * @desc ゲームの基礎言語です。翻訳リソースが見つからない場合この言語から検索します。
 * @type select
 * @default ja-JP
 * @option アラビア語（サウジアラビア）
 * @value ar-SA
 * @option ベンガル語（バングラディシュ）
 * @value bn-BD
 * @option ベンガル語（インド）
 * @value bn-IN
 * @option チェコ語
 * @value cs-CZ
 * @option ドイツ語（デンマーク）
 * @value da-DK
 * @option ドイツ語（オーストリア）
 * @value de-AT
 * @option ドイツ語（スイス）
 * @value de-CH
 * @option ドイツ語（ドイツ）
 * @value de-DE
 * @option ギリシャ語
 * @value el-GR
 * @option 英語（オーストラリア）
 * @value en-AU
 * @option 英語（カナダ）
 * @value en-CA
 * @option 英語（イギリス）
 * @value en-GB
 * @option 英語（アイルランド）
 * @value en-IE
 * @option 英語（インド）
 * @value en-IN
 * @option 英語（ニュージーランド）
 * @value en-NZ
 * @option 英語（アメリカ）
 * @value en-US
 * @option 英語（南アフリカ）
 * @value en-ZA
 * @option スペイン語（アルゼンチン）
 * @value es-AR
 * @option スペイン語（チリ）
 * @value es-CL
 * @option スペイン語（コロンビア）
 * @value es-CO
 * @option スペイン語（スペイン）
 * @value es-ES
 * @option スペイン語（メキシコ）
 * @value es-MX
 * @option スペイン語（アメリカ）
 * @value es-US
 * @option フィンランド語
 * @value fi-FI
 * @option フランス語（ベルギー）
 * @value fr-BE
 * @option フランス語（カナダ）
 * @value fr-CA
 * @option フランス語（スイス）
 * @value fr-CH
 * @option フランス語（フランス）
 * @value fr-FR
 * @option ヘブライ語
 * @value he-IL
 * @option ヒンディー語
 * @value hi-IN
 * @option ハンガリー語
 * @value hu-HU
 * @option インドネシア語
 * @value id-ID
 * @option イタリア語（スイス）
 * @value it-CH
 * @option イタリア語（イタリア）
 * @value it-IT
 * @option 日本語
 * @value ja-JP
 * @option 韓国語
 * @value ko-KR
 * @option オランダ語（ベルギー）
 * @value nl-BE
 * @option オランダ語（オランダ）
 * @value nl-NL
 * @option ノルウェー語
 * @value no-NO
 * @option ポーランド語
 * @value pl-PL
 * @option ポルトガル語（ブラジル）
 * @value pt-BR
 * @option ポルトガル語（ポルトガル）
 * @value pt-PT
 * @option ルーマニア語
 * @value ro-RO
 * @option ロシア語
 * @value ru-RU
 * @option スロバキア語
 * @value sk-SK
 * @option スウェーデン語
 * @value sv-SE
 * @option タミル語（インド）
 * @value ta-IN
 * @option タミル語（スリランカ）
 * @value ta-LK
 * @option タイ語
 * @value th-TH
 * @option トルコ語
 * @value tr-TR
 * @option 中国語（簡体字）
 * @value zh-CN
 * @option 中国語（繁体字）
 * @value zh-TW
 *
 * @param language
 * @text 使用言語
 * @desc ゲームで使用する言語です。
 * @type select
 * @default ja-JP
 * @option アラビア語（サウジアラビア）
 * @value ar-SA
 * @option ベンガル語（バングラディシュ）
 * @value bn-BD
 * @option ベンガル語（インド）
 * @value bn-IN
 * @option チェコ語
 * @value cs-CZ
 * @option ドイツ語（デンマーク）
 * @value da-DK
 * @option ドイツ語（オーストリア）
 * @value de-AT
 * @option ドイツ語（スイス）
 * @value de-CH
 * @option ドイツ語（ドイツ）
 * @value de-DE
 * @option ギリシャ語
 * @value el-GR
 * @option 英語（オーストラリア）
 * @value en-AU
 * @option 英語（カナダ）
 * @value en-CA
 * @option 英語（イギリス）
 * @value en-GB
 * @option 英語（アイルランド）
 * @value en-IE
 * @option 英語（インド）
 * @value en-IN
 * @option 英語（ニュージーランド）
 * @value en-NZ
 * @option 英語（アメリカ）
 * @value en-US
 * @option 英語（南アフリカ）
 * @value en-ZA
 * @option スペイン語（アルゼンチン）
 * @value es-AR
 * @option スペイン語（チリ）
 * @value es-CL
 * @option スペイン語（コロンビア）
 * @value es-CO
 * @option スペイン語（スペイン）
 * @value es-ES
 * @option スペイン語（メキシコ）
 * @value es-MX
 * @option スペイン語（アメリカ）
 * @value es-US
 * @option フィンランド語
 * @value fi-FI
 * @option フランス語（ベルギー）
 * @value fr-BE
 * @option フランス語（カナダ）
 * @value fr-CA
 * @option フランス語（スイス）
 * @value fr-CH
 * @option フランス語（フランス）
 * @value fr-FR
 * @option ヘブライ語
 * @value he-IL
 * @option ヒンディー語
 * @value hi-IN
 * @option ハンガリー語
 * @value hu-HU
 * @option インドネシア語
 * @value id-ID
 * @option イタリア語（スイス）
 * @value it-CH
 * @option イタリア語（イタリア）
 * @value it-IT
 * @option 日本語
 * @value ja-JP
 * @option 韓国語
 * @value ko-KR
 * @option オランダ語（ベルギー）
 * @value nl-BE
 * @option オランダ語（オランダ）
 * @value nl-NL
 * @option ノルウェー語
 * @value no-NO
 * @option ポーランド語
 * @value pl-PL
 * @option ポルトガル語（ブラジル）
 * @value pt-BR
 * @option ポルトガル語（ポルトガル）
 * @value pt-PT
 * @option ルーマニア語
 * @value ro-RO
 * @option ロシア語
 * @value ru-RU
 * @option スロバキア語
 * @value sk-SK
 * @option スウェーデン語
 * @value sv-SE
 * @option タミル語（インド）
 * @value ta-IN
 * @option タミル語（スリランカ）
 * @value ta-LK
 * @option タイ語
 * @value th-TH
 * @option トルコ語
 * @value tr-TR
 * @option 中国語（簡体字）
 * @value zh-CN
 * @option 中国語（繁体字）
 * @value zh-TW
 *
 * @param resources
 * @text 使用リソース
 * @desc 読み込み対象のリソースファイルを指定して下さい。
 * @type string[]
 * @default []
 *
 * @param comment
 * @text 備考欄
 * @desc プラグイン側では使用しません。
 *       メモ欄としてお使いください。
 * @type multiline_string
 * @default
 *
 */
(() => {
	"use strict";

    const pluginName = "TextResource";
    const script = document.currentScript;
    const param  = PluginManagerEx.createParameter(script);

    const LANGUAGES = {
        ARABIC: "ar-SA",
        BANGLA: "bn-BD",
        BANGLA_INDIA: "bn-IN",
        CZECH: "cs-CZ",
        GERMAN_DENMARK: "da-DK",
        GERMAN_AUSTRIA: "de-AT",
        GERMAN_SWISS: "de-CH",
        GERMAN: "de-DE",
        GREEK: "el-GR",
        ENGLISH_AUSTRALIA: "en-AU",
        ENGLISH_CANADA: "en-CA",
        ENGLISH_GB: "en-GB",
        ENGLISH_IRELAND: "en-IE",
        ENGLISH_INDIA: "en-IN",
        ENGLISH_NZ: "en-NZ",
        ENGLISH_US: "en-US",
        ENGLISH_SA: "en-ZA",
        SPANISH_AR: "es-AR",
        SPANISH_CL: "es-CL",
        SPANISH_CL: "es-CO",
        SPANISH: "es-ES",
        SPANISH_MEXICO: "es-MX",
        SPANISH_US: "es-US",
        FINNISH: "fi-FI",
        FRENCH_BR: "fr-BE",
        FRENCH_CA: "fr-CA",
        FRENCH_SWISS: "fr-CH",
        FRENCH: "fr-FR",
        HEBREW: "he-IL",
        HINDI: "hi-IN",
        HANGARIAN: "hu-HU",
        INDONESIAN: "id-ID",
        ITALIAN_SWISS: "it-CH",
        ITALIAN: "it-IT",
        JAPANESE: "ja-JP",
        KOREAN: "ko-KR",
        DUTCH_BEKGIUM: "nl-BE",
        DUTCH: "nl-NL",
        NORWEGIAN: "no-NO",
        POLISH: "pl-PL",
        PORTUGESE_BRAZIL: "pt-BR",
        PORTUGESE: "pt-PT",
        ROMANIAN: "ro-RO",
        RUSSIAN: "ru-RU",
        SLOVAK: "sk-SK",
        SWEDISH: "sv-SE",
        TAMIL_INDIA: "ta-IN",
        TAMIL_SRILANKA: "ta-LK",
        THAI: "th-TH",
        TURKISH: "tr-TR",
        CHINESE: "zh-CN",
        CHINESE_TAIWAN: "zh-TW",
    };
    window.LANGUAGES = Object.freeze(LANGUAGES);

    const BUILT_IN_RESOURCES = [
        "SystemText",
    ];

    /********************************************************************************************************
     * 共有基盤
     ********************************************************************************************************/
    const findLanguages = (basePath) => {
        return Object.values(LANGUAGES).filter(lang => {
            return PluginUtils.fileExists(basePath, lang);
        });
    };

    const fileExists = (basePath, lang, filename) => {
        const fn = `${lang}/${filename}.json`;
        return PluginUtils.fileExists(basePath, fn);
    };

    const loadResourcesAsync = () => {
        const targetFiles = BUILT_IN_RESOURCES.concat(param.resources);
        const path = 'data/resources';

        const targetDirs = findLanguages(path);

        try {
            return targetDirs.map(lang => {
                return targetFiles.filter(fileName => !!fileName)
                    .filter(fileName => fileExists(path, lang, fileName))
                    .map(fileName => {
                        return PluginUtils.loadJsonAsync(path, lang, fileName);
                    });
            }).flat();
        } catch (err) {
            Logger.e(`loadResourcesAsync: error = ${err}`);
        }
        return [];
    };

    //========================================================================
    // コアスクリプト変更部 (Game_Message)
    //========================================================================
    const replaceLabel = (baseText) => {
        const pattern = /^##\w+/g;
        const matches = baseText.match(pattern);
        if (!!matches) {
            const label = matches[0].replace('##', '');
            return baseText.replace(pattern, TextResource.getText(label));
        }
        return baseText;
    };

    const _Game_Message_prototype_add = Game_Message.prototype.add;
    Game_Message.prototype.add = function(text) {
        this._texts.push(replaceLabel(text));
    };

    const _Game_Message_prototype_setChoices = Game_Message.prototype.setChoices;
    Game_Message.prototype.setChoices = function(choices, defaultType, cancelType) {
        _Game_Message_prototype_setChoices.apply(this, [
            choices.map(choice => replaceLabel(choice)),
            defaultType,
            cancelType
        ]);
    };

    //========================================================================
    // リソースのロード
    //========================================================================
    const _Scene_Boot_prototype_onDatabaseLoaded = Scene_Boot.prototype.onDatabaseLoaded;
    Scene_Boot.prototype.onDatabaseLoaded = function() {
        _Scene_Boot_prototype_onDatabaseLoaded.apply(this, arguments);
        const load = async () => {
            TextResource.textLabels = {
                baseLanguage: param.baseLanguage,
                language: param.language,
                resources: Object.values(LANGUAGES).map(lang => {
                    return {};
                }),
            };

            try {
                const promises = loadResourcesAsync();
                Promise.all(promises).then(result => {
                    result.forEach(res => {
                        TextResource.registerResources(res.subDir, res.json);
                    });

                    TextResource.isLoaded = true;
                    TextResource.listeners.forEach(l => l());
                    TextResource.listeners = [];
                }).catch(err => {
                    Logger.d(`error occurred: err = ${err}`);
                });
            } catch (err) {
                Logger.d(`error occurred: err = ${err}`);
            }

            Logger.d('Game System start');
        };
        load();
    };

    //========================================================================
    // TextResourceクラス
    //========================================================================
    const _Scene_Title_isReady = Scene_Title.prototype.isReady;
    Scene_Title.prototype.isReady = function() {
        return _Scene_Title_isReady.apply(this, arguments) && TextResource.isLoaded;
    };

    //========================================================================
    // TextResourceクラス
    //========================================================================
    class TextResource {
        static textLabels;
        static isLoaded = false;
        static listeners = [];

        constructor() {

        }

        static addOnLoadedListener(l) {
            if (!!l && typeof l === 'function') {
                if (TextResource.isLoaded === true) {
                    l();
                } else {
                    TextResource.listeners.push(l);
                }
            }
        }

        static changeLanguage(newLanguage) {
            if (LANGUAGES.some(lang => newLanguage === lang)) {
                TextResource.textLabels.language = newLanguage;
            }
        }

        static getBaseLanguage() {
            return TextResource.textLabels.baseLanguage;
        }

        static getCurrentLanguage() {
            return TextResource.textLabels.language;
        }

        static format(label, ...args) {
            return TextResource.getText(label).format(...args);
        }

        static getText(label) {
            if (TextResource.hasResourceInLocal(label)) {
                const language = TextResource.getCurrentLanguage();
                return TextResource.textLabels.resources[language][label];
            } else if (TextResource.hasResource(label)) {
                const baseLanguage = TextResource.getBaseLanguage();
                return TextResource.textLabels.resources[baseLanguage][label];
            } else {
                if (DebugSwitch.isEnable()) {
                    throw new Error(`TextResource: [UNKNOWN LABEL: ${label}]`);
                } else {
                    Logger.d(`TextResource: [UNKNOWN LABEL: ${label}]`);
                    return '';
                }
            }
        }

        static hasResourceInLocal(label) {
            if (!!label && label.length > 0) {
                const language = TextResource.getCurrentLanguage();
                if (!!TextResource.textLabels.resources[language]) {
                    return TextResource.textLabels.resources[language].hasOwnProperty(label);
                }
            }
            return false;
        }

        static hasResource(label) {
            const baseLanguage = TextResource.getBaseLanguage();
            if (!!label && label.length > 0) {
                if (!!TextResource.textLabels.resources[baseLanguage]) {
                    return TextResource.textLabels.resources[baseLanguage].hasOwnProperty(label);
                }
            }
            return false;
        }

        static registerResource(language, label, text) {
            if (TextResource.textLabels.resources[language] == null) {
                TextResource.textLabels.resources[language] = {};
            }
            TextResource.textLabels.resources[language][label] = text;
        }

        static registerResources(language, list) {
            Object.keys(list).filter(key => {
                return key !== 'version' && key !== 'language' && key !== 'game' && key !== 'metadata';
            }).forEach(label => {
                // Logger.d(`registerResources: label = ${label}`);
                TextResource.registerResource(language, label, list[label]);
            });
        }
    };
    window.TextResource = TextResource;
})();
