/*
 *  localelistmodel.cpp
 *  SPDX-FileCopyrightText: 2014 Sebastian Kügler <sebas@kde.org>
 *  SPDX-FileCopyrightText: 2021 Han Young <hanyoung@protonmail.com>
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "localelistmodel.h"
#include "exampleutility.h"

#include "config-workspace.h"
#include "glibclocaleconstructor.h"

using namespace Qt::StringLiterals;
using namespace KCM_RegionAndLang;

LocaleListModel::LocaleListModel(QObject *parent)
    : QAbstractListModel(parent)
{
    const QList<QLocale> m_locales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
    m_localeData.reserve(m_locales.size() + 1);
    // we use first QString for title in Unset option
    m_localeData.push_back(LocaleData{i18n("Default for System"), QString(), QString(), QString(), i18n("Default"), QLocale()});
    for (auto &locale : m_locales) {
#ifdef GLIBC_LOCALE
        // filter out invalid glibc locales from icu locales
        if (!GlibcLocaleConstructor::instance()->hasGlibcLocale(locale.name())) {
            continue;
        }
#endif

        if (locale == QLocale::system()) {
            continue;
        }

        switch (locale.language()) {
        case QLocale::Chinese:
            if (locale.script() == QLocale::LatinScript || (locale.territory() == QLocale::HongKong && locale.script() == QLocale::SimplifiedChineseScript)) {
                continue;
            }
            break;
        case QLocale::Hindi:
        case QLocale::Inuktitut:
        case QLocale::Konkani:
            if (locale.script() == QLocale::LatinScript) {
                continue;
            }
            break;
        case QLocale::Serbian:
            if (locale.script() == QLocale::LatinScript) {
                if (locale.territory() == QLocale::Serbia) {
                    m_localeData.push_back(LocaleData{.nativeName = locale.nativeLanguageName(),
                                                      .englishName = QLocale::languageToString(locale.language()),
                                                      .nativeCountryName = locale.nativeCountryName(),
                                                      .englishCountryName = QLocale::countryToString(locale.country()),
                                                      .countryCode = QStringLiteral("sr_RS@latin.UTF-8"),
                                                      .locale = locale});
                }
                continue;
            }
            break;
        case QLocale::Kashmiri:
            if (locale.script() != QLocale::ArabicScript) {
                continue;
            }
            break;
        case QLocale::Manipuri:
            if (locale.script() != QLocale::BanglaScript) {
                continue;
            }
            break;
        case QLocale::Mongolian:
            if (locale.script() != QLocale::CyrillicScript) {
                continue;
            }
            break;
        case QLocale::Santali:
            if (locale.script() != QLocale::DevanagariScript) {
                continue;
            }
            break;
        case QLocale::Azerbaijani:
        case QLocale::Bosnian:
        case QLocale::English:
        case QLocale::Fulah:
        case QLocale::Hausa:
        case QLocale::Malay:
        case QLocale::Uzbek:
            if (locale.script() != QLocale::LatinScript) {
                continue;
            }
            break;

        default:
            break;
        }

        m_localeData.push_back(LocaleData{.nativeName = locale.nativeLanguageName(),
                                          .englishName = QLocale::languageToString(locale.language()),
                                          .nativeCountryName = locale.nativeCountryName(),
                                          .englishCountryName = QLocale::countryToString(locale.country()),
                                          .countryCode = locale.name(),
                                          .locale = locale});
    }
}

int LocaleListModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return m_localeData.size();
}

QVariant LocaleListModel::data(const QModelIndex &index, int role) const
{
    int dataIndex = index.row();
    const auto &data = m_localeData.at(dataIndex);
    switch (static_cast<RoleName>(role)) {
    case FlagIcon: {
        QString countryCode;
        const QStringList split = data.countryCode.split(QLatin1Char('_'));
        if (split.size() > 1) {
            countryCode = split[1].toLower();
        }
        return "image://flags/%1"_L1.arg(countryCode);
    }
    case DisplayName: {
        // 0 is unset option, 1 is locale C
        if (dataIndex == 1) {
            return data.countryCode;
        }
        const QString clabel = !data.nativeCountryName.isEmpty() ? data.nativeCountryName : data.englishCountryName;
        QString languageName;
        if (!data.nativeName.isEmpty()) {
            languageName = data.nativeName;
        } else {
            languageName = data.englishName;
        }
        if (dataIndex == 0) {
            return languageName;
        }
        return i18nc("the first is language name, the second is the country name, like 'English (America)'", "%1 (%2)", languageName, clabel);
    }
    case LocaleName: {
        QString cvalue = data.countryCode;
        if (!cvalue.contains(QLatin1Char('.')) && cvalue != QLatin1Char('C') && cvalue != i18n("Default")) {
            // explicitly add the encoding,
            // otherwise Qt doesn't accept dead keys and garbles the output as well
            cvalue.append(QLatin1String(".UTF-8"));
        }
        return cvalue;
    }
    case Example: {
        switch (m_configType) {
        case Lang:
        case Language:
            Q_ASSERT(false); // shouldn't happen
            return {};
        case Numeric:
            return Utility::numericExample(data.locale);
        case Time:
            return Utility::timeExample(data.locale);
        case Currency:
            return Utility::monetaryExample(data.locale);
        case Measurement:
            return Utility::measurementExample(data.locale);
        case PaperSize:
            return Utility::paperSizeExample(data.locale);
#ifdef LC_ADDRESS
        case Address:
            return Utility::addressExample(data.locale);
        case NameStyle:
            return Utility::nameStyleExample(data.locale);
        case PhoneNumbers:
            return Utility::phoneNumbersExample(data.locale);
#endif
        case BinaryDialect:
            Q_ASSERT(false);
            break;
        }
        return {};
    }
    case FilterRole: {
        return QString(data.englishCountryName.toLower() + data.nativeCountryName.toLower() + data.nativeName.toLower() + data.englishName.toLower()
                       + data.countryCode.toLower());
    }
    }
    Q_UNREACHABLE();
    return {};
}

QHash<int, QByteArray> LocaleListModel::roleNames() const
{
    return {{LocaleName, QByteArrayLiteral("localeName")},
            {DisplayName, QByteArrayLiteral("display")},
            {FlagIcon, QByteArrayLiteral("flag")},
            {Example, QByteArrayLiteral("example")},
            {FilterRole, QByteArrayLiteral("filter")}};
}

int LocaleListModel::selectedConfig() const
{
    return m_configType;
}

void LocaleListModel::setSelectedConfig(int config)
{
    if (config != m_configType) {
        m_configType = static_cast<SettingType>(config);
    }
    Q_EMIT selectedConfigChanged();
    Q_EMIT dataChanged(createIndex(0, 0), createIndex(rowCount(), 0), QList<int>(1, Example));
}

void LocaleListModel::setLang(const QString &lang)
{
    QString tmpLang = lang;
    bool isC = false;
    if (lang.isEmpty()) {
        tmpLang = qEnvironmentVariable("LANG");
        if (tmpLang.isEmpty()) {
            tmpLang = QStringLiteral("C");
            isC = true;
        }
    }

    LocaleData &data = m_localeData.front();
    if (isC) {
        data.nativeName = i18nc("@info:title, meaning the current locale is system default(which is `C`)", "System Default C");
    } else {
        data.nativeName =
            i18nc("@info:title the current locale is the default for %1, %1 is the country name", "Default for %1", QLocale(tmpLang).nativeLanguageName());
    }
    data.locale = QLocale(tmpLang);

    Q_EMIT dataChanged(createIndex(0, 0), createIndex(0, 0));
}

#include "moc_localelistmodel.cpp"
