/*
 * Copyright (C) 2023, KylinSoft Co., Ltd.
 *
 * 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, or (at your option)
 * 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, see <http://www.gnu.org/licenses/>.
 *
**/
#include "area.h"
#include <QDebug>
#include <QDateTime>
#include <QMessageBox>

Area::Area()
    : mFirstLoad(true)
{
    pluginName = tr("Area");
    pluginType = DATETIME;
}

Area::~Area()
{
    if (areaWidget) {
        delete areaWidget;
        areaWidget = nullptr;
    }
    if (areaInterface) {
        delete areaInterface;
        areaInterface = nullptr;
    }
}

void Area::cloudChangedSlot(const QString &key)
{
    if(key == QString("area")) {
        initCountry();
        initCalendar();
        initFirstDay();
#ifdef Nile
        initDateComboBox();
#else
        initDateFormat();
#endif
        initTimeFormat();
    }
}

void Area::connectToServer()
{
    QThread *NetThread = new QThread;
    MThread *NetWorker = new MThread;
    NetWorker->moveToThread(NetThread);
    connect(NetThread, &QThread::started, NetWorker, &MThread::run);
    connect(NetWorker,&MThread::keychangedsignal,this,&Area::cloudChangedSlot);
    connect(NetThread, &QThread::finished, NetWorker, &MThread::deleteLater);
    NetThread->start();
}

QString Area::plugini18nName()
{
    return pluginName;
}

int Area::pluginTypes()
{
    return pluginType;
}

QWidget *Area::pluginUi()
{
    if (mFirstLoad) {
        mFirstLoad    = false;
        areaWidget    = new AreaUi;
        areaInterface = new QDBusInterface("org.ukui.ukcc.session",
                                           "/Area",
                                           "org.ukui.ukcc.session.Area",
                                           QDBusConnection::sessionBus(), this);

        if (areaInterface->isValid()) { // 判断服务是否存在
            QDBusMessage message = areaInterface->call("ping"); // 判断dbus路径是否存在
            if (message.type() == QDBusMessage::ErrorMessage && message.errorMessage().contains("No such object path", Qt::CaseInsensitive)) {
                qWarning()<<areaInterface<<":"<<message.errorMessage();
            } else {
                initContent();
                connectToServer();
                if (UkccCommon::isTablet()) {
                    areaWidget->settingForIntel();
                }
                QDBusConnection::sessionBus().connect("org.ukui.ukcc.session",
                                                      "/Area",
                                                      "org.ukui.ukcc.session.Area",
                                                      "changed",
                                                      this,
                                                      SLOT(dataChanged(QString)));
            }

        } else {
            qCritical() << "org.ukui.ukcc.session.Area DBus error:" << areaInterface->lastError();
        }

    } else {
        // 有可能修改了日期，因此重新加载日期格式
        if (areaInterface->isValid()) {
#ifndef Nile
            initDateFormat();
#endif
        }
    }
    return areaWidget;
}

const QString Area::name() const
{
    return QStringLiteral("Area");
}

bool Area::isShowOnHomePage() const
{
    return true;
}

QIcon Area::icon() const
{
    return QIcon::fromTheme("ukui-area-symbolic");
}

bool Area::isEnable() const
{
    return true;
}

void Area::dataChanged(QString key)
{
    if (changeKey != key) {
        if (key == QString("formatCountry")) {
            initCountry();
        } else if (key == QString("calendar")) {
            initCalendar();
        } else if (key == QString("firstDay")) {
            initFirstDay();
        } else if (key == QString("dateFormat")) {
#ifndef Nile
            initDateFormat();
#endif
        } else if (key == QString("timeFormat")) {
#ifndef Nile
            initTimeFormat();
#endif
        } else if (key == QString("showLanguageList") || key == QString("language")) {
            initLanguage();
        } else if (key == "iconThemeName") {
            areaWidget->reloadLanguageFrameIcon();
        }
    }
    changeKey = "";
}

void Area::initContent()
{
    initCountry();
    initCalendar();
    initFirstDay();
    initDateFormat();
    initTimeFormat(true);
    initLanguage();
    initAddLanguage();
#ifdef Nile
    initDateComboBox();
#endif
    initConnect();
}

InteractiveInfo Area::initInteractiveInfo(int orderNum)
{
    InteractiveInfo info;
    if (orderNum == AreaUi::COUNTRY) {
        info.listKey = QString("formatCountryList");
        info.key     = QString("formatCountry");
        info.setkey  = QString("setFormatCountry");
        info.list    = {{QString("en_US.UTF-8"), tr("English  (US)")},
                        {QString("zh_CN.UTF-8"), tr("Simplified Chinese  (CN)")},
                        {QString("bo_CN.UTF-8"), tr("Tibetan  (CN)")}};
    } else if (orderNum == AreaUi::CALENDAR) {
        info.listKey = QString("calendarList");
        info.key     = QString("calendar");
        info.setkey  = QString("setCalendar");
        info.list    = {{QString("solarlunar"), tr("Solar calendar")},
                        {QString("lunar"),      tr("Lunar")}};
    } else if (orderNum == AreaUi::FIRSTDAY) {
        info.listKey = QString("firstDayList");
        info.key     = QString("firstDay");
        info.setkey  = QString("setFirstDay");
        info.list    = {{QString("monday"), tr("Monday")},
                        {QString("sunday"), tr("Sunday")}};
    } else if (orderNum == AreaUi::DATEFORMAT) {
        info.listKey = QString("dateFormatList");
        info.key     = QString("dateFormat");
        info.setkey  = QString("setDateFormat");
        info.list    = {{QString("cn"), QDateTime::currentDateTime().toString("yyyy/MM/dd")},
                        {QString("en"), QDateTime::currentDateTime().toString("yyyy-MM-dd")}};
    } else if (orderNum == AreaUi::TIMEFORMAT) {
        info.listKey = QString("timeFormatList");
        info.key     = QString("timeFormat");
        info.setkey  = QString("setTimeFormat");
        info.list    = {{QString("12"), tr("12 Hours")},
                        {QString("24"), tr("24 Hours")}};
    }
    return info;
}

void Area::initComboBox(QComboBox *comboBox, InteractiveInfo info)
{
    if (!comboBox) {
        return;
    }
    comboBox->disconnect();
    comboBox->clear();
    QStringList dataList = {};
    for (pairString s : info.list) {
        dataList.append(s.first);
    }
    for (QString s : areaInterface->property(info.listKey.toUtf8().data()).toStringList()) {
        bool addFlag = false;
        for (int i = 0; i < dataList.size(); ++i) {
            if (dataList.at(i) == s) {
                comboBox->addItem(info.list.at(i).second, info.list.at(i).first);
                addFlag = true;
                break;
            }
        }
        if (!addFlag) {
             comboBox->addItem(s, s);
        }
    }
    int index = comboBox->findData(areaInterface->property(info.key.toUtf8().data()).toString());
    comboBox->setCurrentIndex(index < 0 ? 0 : index);
    connect(comboBox,
            static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
            areaWidget,
            [=](int num) {
                Q_UNUSED(num);
                changeKey = info.key;
                areaInterface->call(info.setkey.toUtf8().data(), comboBox->currentData().toString());
                UkccCommon::buriedSettings(name(), info.setkey, QString("select"), comboBox->currentData().toString());
                if (info.setkey == QString("setFormatCountry")) {
                    showMessageBox(1);
                }
    });
}

void Area::initCountry()
{
    initComboBox(areaWidget->countryComboBox(), initInteractiveInfo(AreaUi::COUNTRY));
}

void Area::initCalendar()
{
    initComboBox(areaWidget->calendarComboBox(), initInteractiveInfo(AreaUi::CALENDAR));
}

void Area::initFirstDay()
{
    initComboBox(areaWidget->firstDayComboBox(), initInteractiveInfo(AreaUi::FIRSTDAY));
}

void Area::initDateFormat()
{
#ifdef Nile
    qDebug() << "fjoiwiejofiwojefoiwajeoifjowaiejfoiawjeofiajwoeifjoiweofa";
    QString currentsecStr;
        QDateTime current = QDateTime::currentDateTime();

        if (areaWidget->countryComboBox()->currentIndex() == 0) {
            currentsecStr = current.toString("M.d.yy");
            areaWidget->shortDateComboBox()->addItem(currentsecStr);

            currentsecStr = current.toString("M/d/yy");
            areaWidget->shortDateComboBox()->addItem(currentsecStr);

            currentsecStr = current.toString("M-d-yy");
            areaWidget->shortDateComboBox()->addItem(currentsecStr);

            currentsecStr = current.toString("MM.dd.yyyy");
            areaWidget->shortDateComboBox()->addItem(currentsecStr);

            currentsecStr = current.toString("MM/dd/yyyy");
            areaWidget->shortDateComboBox()->addItem(currentsecStr);

            currentsecStr = current.toString("MM-dd-yyyy");
            areaWidget->shortDateComboBox()->addItem(currentsecStr);
        } else {
            currentsecStr = current.toString("yy.M.d");
            areaWidget->shortDateComboBox()->addItem(currentsecStr);

            currentsecStr = current.toString("yy/M/d");
            areaWidget->shortDateComboBox()->addItem(currentsecStr);

            currentsecStr = current.toString("yy-M-d");
            areaWidget->shortDateComboBox()->addItem(currentsecStr);

            currentsecStr = current.toString("yyyy.MM.dd");
            areaWidget->shortDateComboBox()->addItem(currentsecStr);

            currentsecStr = current.toString("yyyy/MM/dd");
            areaWidget->shortDateComboBox()->addItem(currentsecStr);

            currentsecStr = current.toString("yyyy-MM-dd");
            areaWidget->shortDateComboBox()->addItem(currentsecStr);
        }

        QLocale locale = QLocale::system();
        if ("zh_CN" == locale.name()){
            locale = QLocale::Chinese;
        } else {
            locale = QLocale::English;
        }
        currentsecStr = locale.toString(current, tr("MMMM dd, yyyy"));
        areaWidget->longDateComboBox()->addItem(currentsecStr);

        currentsecStr = locale.toString(current, tr("MMMM d, yy"));
        areaWidget->longDateComboBox()->addItem(currentsecStr);
        initDateComboBox();
#else
    initComboBox(areaWidget->dateComboBox(), initInteractiveInfo(AreaUi::DATEFORMAT));
#endif
}

void Area::initTimeFormat(bool firstLoad)
{
#ifndef Nile
    Q_UNUSED(firstLoad)
    initComboBox(areaWidget->timeComboBox(), initInteractiveInfo(AreaUi::TIMEFORMAT));
#else
    if(firstLoad) {
        areaWidget->timeComboBox()->addItem(tr("12 Hours"), "12");
        areaWidget->timeComboBox()->addItem(tr("24 Hours"), "24");
    }

    QString hourFormat;

    hourFormat = kdk_system_get_now_timeformat();
    hourFormat = hourFormat.left(2);

    if (firstLoad) {
        InteractiveInfo info = initInteractiveInfo(AreaUi::TIMEFORMAT);
        QString orgGsettingFormat = areaInterface->property(info.key.toUtf8().data()).toString().left(2);
        if (hourFormat != orgGsettingFormat) {
            hourFormat = orgGsettingFormat;
            if (hourFormat == "24") {
                kdk_system_set_24_timeformat();
            } else {
                kdk_system_set_12_timeformat();
            }
        }
    }


    if ("24" == hourFormat) {
        areaWidget->timeComboBox()->setCurrentIndex(1);
    } else {
        areaWidget->timeComboBox()->setCurrentIndex(0);
    }
#endif
}

void Area::initLanguage()
{
    areaWidget->clearShowLanguage();
    QStringList showLanguageList = areaInterface->property("showLanguageList" ).toStringList();
    QStringList languageList     = areaInterface->property("languageList").toStringList();
    QString     currentLanguage  = areaInterface->property("language" ).toString();
    if (languageList.contains(currentLanguage)) {
        areaWidget->addShowLanguage(currentLanguage, showLanguageName(currentLanguage), true);
    }
    // Gsetting为空，自动设置显示选中的语言
    if (showLanguageList.isEmpty()) {
        showLanguageList.append(currentLanguage);
        changeKey = QString("showLanguageList");
        areaInterface->call("setShowLanguageList", showLanguageList);
        areaInterface->blockSignals(false);
    } else {
        for (QString language : showLanguageList) {
            if (languageList.contains(language) && language != currentLanguage) {
                areaWidget->addShowLanguage(language, showLanguageName(language), false);
            }
        }
    }
}

void Area::initAddLanguage()
{
    if (!areaWidget->addbutton() || !areaWidget->languageDialog()) {
        return;
    }
    const QStringList languageList = areaInterface->property("languageList" ).toStringList();
    for (QString s : languageList) {
        areaWidget->languageDialog()->addRow(showLanguageName(s));
    }

    connect(areaWidget->addbutton(), &AddButton::clicked, this, [=]() {
        areaWidget->languageDialog()->show();
        UkccCommon::buriedSettings(name(), "add system language", QString("clicked"));
    });
    connect(areaWidget->languageDialog(), &AddLanguageDialog::addShowLanguage, this, [=](QStringList selectedLanguageList) {
        for (QString selectedLanguage : selectedLanguageList) {
            for (int i = 0; i < languageList.size(); ++i) {
                if (selectedLanguage == showLanguageName(languageList.at(i))) {
                    QStringList showLanguageList = areaInterface->property("showLanguageList" ).toStringList();
                    if (showLanguageList.contains(languageList.at(i))) {
                        break;
                    }
                    showLanguageList.append(languageList.at(i));
                    areaWidget->addShowLanguage(languageList.at(i), selectedLanguage, false);
                    changeKey = QString("showLanguageList");
                    areaInterface->call("setShowLanguageList", showLanguageList);
                    if (languageList.at(i) == "bo_CN") {
                        bool addMethod = true;
                        for (QPair<QString,QString>method : AddInputMethodDialog::inputMethodList_bo_CN) {
                            QDBusReply<bool> res = areaInterface->call("isAddedInputMethod", method.first);
                            if (res.isValid() && res.value()) {
                                qInfo()<<"Input Method:"<<method.first<<" already exist.";
                                addMethod = false;
                                break;
                            }
                        }
                        if (addMethod) {
                            areaWidget->inputMethodDialog()->addInputMethod("bo_CN");
                            areaWidget->inputMethodDialog()->show();
                        }
                    }
                    break;
                }
            }
        }
    });
    connect(areaWidget->inputMethodDialog(), &AddInputMethodDialog::inputMethodAdded, this, [=](const QStringList methodList) {
        for (QString method : methodList) {
            qInfo() << "add input method:" << method;
            areaInterface->call("changeInputMethod", method, true);
        }
    });
}

void Area::initConnect()
{
    connect(areaWidget, &AreaUi::languageChanged, this, [=](QString languageCode) {
        changeKey = QString("language");
        areaInterface->call("setLanguage", languageCode);
        UkccCommon::buriedSettings(name(), QString("languageFrame"), QString("clicked"), languageCode);
        showMessageBox(2);
    });
    connect(areaWidget, &AreaUi::showLanguageListRemoved, this, [=](QString languageCode) {
        QStringList showLanguageList = areaInterface->property("showLanguageList" ).toStringList();
        showLanguageList.removeOne(languageCode);
        changeKey = QString("showLanguageList");
        areaInterface->call("setShowLanguageList", showLanguageList);
        UkccCommon::buriedSettings(name(), QString("Delete"), QString("clicked"), languageCode);
    });

#ifdef Nile
    connect(areaWidget->shortDateComboBox(), static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
            [=]{
        kdk_system_set_short_dateformat(areaWidget->shortDateComboBox()->itemText(areaWidget->shortDateComboBox()->currentIndex()).toLatin1().data());
        UkccCommon::buriedSettings(name(), QString("Short Foramt Date"), QString("select"), areaWidget->shortDateComboBox()->currentData().toString());
    });

    connect(areaWidget->longDateComboBox(), static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
            [=]{
        kdk_system_set_long_dateformat(areaWidget->longDateComboBox()->itemText(areaWidget->longDateComboBox()->currentIndex()).toLocal8Bit().data());
        UkccCommon::buriedSettings(name(), QString("Long Format Date"), QString("select"), areaWidget->longDateComboBox()->currentData().toString());
    });

    connect(areaWidget->timeComboBox(), static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
            areaWidget,
            [=](int num) {
                Q_UNUSED(num);
                bool flag_24;
                if (0 == areaWidget->timeComboBox()->currentIndex()) {
                    flag_24 = false;
                    kdk_system_set_12_timeformat();
                } else {
                    flag_24 = true;
                    kdk_system_set_24_timeformat();
                }
                InteractiveInfo info = initInteractiveInfo(AreaUi::TIMEFORMAT);
                areaInterface->call(info.setkey.toUtf8().data(), areaWidget->timeComboBox()->currentData().toString());
                UkccCommon::buriedSettings(name(), info.setkey, QString("select"), areaWidget->timeComboBox()->currentData().toString());
    });

    QDBusConnection::sessionBus().connect("com.kylin.kysdk.DateServer",
                                          "/com/kylin/kysdk/Date",
                                          "com.kylin.kysdk.DateInterface",
                                          "TimeSignal",
                                          this,
                                          SLOT(TimeChanged(QString)));
    QDBusConnection::sessionBus().connect("com.kylin.kysdk.DateServer",
                                          "/com/kylin/kysdk/Date",
                                          "com.kylin.kysdk.DateInterface",
                                          "LongDateSignal",
                                          this,
                                          SLOT(refreshLongDate(QString)));
    QDBusConnection::sessionBus().connect("com.kylin.kysdk.DateServer",
                                          "/com/kylin/kysdk/Date",
                                          "com.kylin.kysdk.DateInterface",
                                          "ShortDateSignal",
                                          this,
                                          SLOT(refreshShortDate(QString)));
#endif
}

void Area::initDateComboBox() {
#ifdef Nile
        refreshShortDate(kdk_system_get_shortformat());
        refreshLongDate(kdk_system_get_longformat());
#endif
}

void Area::TimeChanged(QString time) {
    Q_UNUSED(time);
    initTimeFormat();
    InteractiveInfo info = initInteractiveInfo(AreaUi::TIMEFORMAT);
    areaInterface->call(info.setkey.toUtf8().data(), areaWidget->timeComboBox()->currentData().toString());
}

void Area::refreshLongDate(QString date) {
    QString mLongFormatDate = date;
    int longindex = 0;

    if ((mLongFormatDate.at(mLongFormatDate.length() - 4) == ',')
            || ((mLongFormatDate.at(2) < '0' || mLongFormatDate.at(2) > '9')
                && (mLongFormatDate.at(2) < 'a' || mLongFormatDate.at(2) > 'z')))
    {
        longindex = 1;
     } else {
        longindex = 0;
    }

    if (longindex == areaWidget->longDateComboBox()->currentIndex())
        return;

    areaWidget->longDateComboBox()->setCurrentIndex(longindex);
}

void Area::refreshShortDate(QString date) {
    QString mShortFormatDate = date;
    int shortindex = 0;
    int ansindex = 0;

    if (areaWidget->countryComboBox()->currentIndex() == 0) {
        ansindex = mShortFormatDate.length() - 3;
    } else {
        ansindex = 2;
    }

    if (mShortFormatDate.at(ansindex) == 'M' ||
            mShortFormatDate.at(ansindex) == 'y') {
        shortindex = 3;
        switch (ansindex) {
        case 2:
            ansindex += 2;
            break;
        default:
            ansindex -= 2;
        }
    }

    if (mShortFormatDate.at(ansindex) == '/')
        shortindex += 1;
    if (mShortFormatDate.at(ansindex) == '-')
        shortindex += 2;
    if (shortindex == areaWidget->shortDateComboBox()->currentIndex())
        return;

    areaWidget->shortDateComboBox()->setCurrentIndex(shortindex);
}

QString Area::showLanguageName(QString languageCode)
{
    QString languageName = "";
    if (languageCode == "zh_CN") {
        languageName = QString("简体中文 ") + QString("(%1)").arg(tr("Simplified Chinese"));
    } else if (languageCode == "en") {
        languageName = QString("English ") + QString("(%1)").arg(tr("English"));
    } else if (languageCode == "bo_CN") {
        languageName = QString("བོད་ཡིག ") + QString("(%1)").arg(tr("Tibetan"));
    } else if (languageCode == "kk_KZ") {
        languageName = QString("Қазақша") + QString("(%1)").arg(tr("Kazakhstan"));
    } else if (languageCode == "ug_CN") {
        languageName = QString("ئۇيغۇر") + QString("(%1)").arg(tr("Uygur"));
    } else if (languageCode == "ky_KG") {
        languageName = QString("Коргизи") + QString("(%1)").arg(tr("Kirghiz"));
    } else if (languageCode == "zh_HK") {
        languageName = QString("繁體") + QString("(%1)").arg(tr("Traditional Chinese"));
    } else if (languageCode == "mn_MN") {
        languageName = QString("Монгол хэл") + QString("(%1)").arg(tr("Mongolian"));
    } else if (languageCode == "de_DE") {
        languageName = QString("Deutsch") + QString("(%1)").arg(tr("German"));
    } else if (languageCode == "es_ES") {
        languageName = QString("Español") + QString("(%1)").arg(tr("Spanish"));
    } else if (languageCode == "fr_FR") {
        languageName = QString("Français") + QString("(%1)").arg(tr("French"));
    } else {
        languageName = QString("languageCode ") + QString("(%1)").arg("languageCode");
    }
    return languageName;
}

void Area::showMessageBox(int flag)
{
    QMessageBox msg(qApp->activeWindow());
    msg.setIcon(QMessageBox::Warning);

    if (flag == 1) {
        msg.setText(tr("Modify the current region need to logout to take effect, whether to logout?"));
        msg.addButton(tr("Logout later"), QMessageBox::NoRole);
        msg.addButton(tr("Logout now"), QMessageBox::ApplyRole);
    } else if(flag == 2) {
        msg.setText(tr("Modify the first language need to reboot to take effect, whether to reboot?"));
        msg.addButton(tr("Reboot later"), QMessageBox::NoRole);
        msg.addButton(tr("Reboot now"), QMessageBox::ApplyRole);
    }
    int ret = msg.exec();

    if (ret == 1) {
        if (flag == 1) {
            system("ukui-session-tools --logout");
        } else if (flag == 2) {
            system("ukui-session-tools --reboot");
        }
    }
    return;
}
