/*  -*- c++ -*-
    SPDX-FileCopyrightText: 2008 Thomas McGuire <Thomas.McGuire@gmx.net>
    SPDX-FileCopyrightText: 2008 Edwin Schepers <yez@familieschepers.nl>
    SPDX-FileCopyrightText: 2004 Marc Mutz <mutz@kde.org>

    SPDX-License-Identifier: LGPL-2.1-or-later
*/

#include "signatureconfigurator.h"
#include "identity.h"
#include "signaturerichtexteditor_p.h"

#include <KActionCollection>
#include <KLineEdit>
#include <KLocalizedString>
#include <KMessageBox>
#include <KToolBar>
#include <QUrl>

#include <KPIMTextEdit/RichTextComposer>
#include <KPIMTextEdit/RichTextComposerControler>
#include <KPIMTextEdit/RichTextComposerImages>
#include <TextCustomEditor/RichTextEditor>

#include <QCheckBox>
#include <QComboBox>
#include <QDir>
#include <QFileInfo>
#include <QLabel>
#include <QStackedWidget>

#include <QHBoxLayout>
#include <QVBoxLayout>

#include <QStandardPaths>

#include <TextCustomEditor/RichTextEditorWidget>

using namespace KIdentityManagementWidgets;

namespace KIdentityManagementWidgets
{
/**
   Private class that helps to provide binary compatibility between releases.
   @internal
  */
//@cond PRIVATE
class Q_DECL_HIDDEN SignatureConfiguratorPrivate
{
public:
    explicit SignatureConfiguratorPrivate(SignatureConfigurator *parent);
    void init();
    // Returns the current text of the textedit as HTML code, but strips
    // unnecessary tags Qt inserts
    [[nodiscard]] QString asCleanedHTML() const;

    QString imageLocation;
    SignatureConfigurator *const q;
    QCheckBox *mEnableCheck = nullptr;
    QCheckBox *mHtmlCheck = nullptr;
    QPushButton *mEditButton = nullptr;
    KToolBar *mEditToolBar = nullptr;
    KToolBar *mFormatToolBar = nullptr;
    KPIMTextEdit::RichTextComposer *mTextEdit = nullptr;
    bool inlinedHtml = false;
};
//@endcond

SignatureConfiguratorPrivate::SignatureConfiguratorPrivate(SignatureConfigurator *parent)
    : q(parent)
    , inlinedHtml(true)
{
}

QString SignatureConfiguratorPrivate::asCleanedHTML() const
{
    QString text = mTextEdit->toHtml();

    // Beautiful little hack to find the html headers produced by Qt.
    QTextDocument textDocument;
    const QString html = textDocument.toHtml();

    // Now remove each line from the text, the result is clean html.
    const QStringList lst = html.split(QLatin1Char('\n'));
    for (const QString &line : lst) {
        text.remove(line + QLatin1Char('\n'));
    }
    return text;
}

void SignatureConfiguratorPrivate::init()
{
    auto vlay = new QVBoxLayout(q);
    vlay->setObjectName(QLatin1StringView("main layout"));

    // "enable signature" checkbox:
    mEnableCheck = new QCheckBox(i18n("&Enable signature"), q);
    mEnableCheck->setWhatsThis(
        i18n("Check this box if you want KMail to append a signature to mails "
             "written with this identity."));
    vlay->addWidget(mEnableCheck);

    // "obtain signature text from" combo and label:
    auto hlay = new QHBoxLayout(); // inherits spacing
    vlay->addLayout(hlay);

    // widget stack that is controlled by the source combo:
    auto widgetStack = new QStackedWidget(q);
    widgetStack->setEnabled(false); // since !mEnableCheck->isChecked()
    vlay->addWidget(widgetStack, 1);
    // connects for the enabling of the widgets depending on
    // signatureEnabled:
    q->connect(mEnableCheck, &QCheckBox::toggled, widgetStack, &QStackedWidget::setEnabled);
    // The focus might be still in the widget that is disabled
    q->connect(mEnableCheck, &QCheckBox::clicked, mEnableCheck, qOverload<>(&QCheckBox::setFocus));

    int pageno = 0;
    // page 0: input field for direct entering:
    auto page = new QWidget(widgetStack);
    widgetStack->insertWidget(pageno, page);
    auto page_vlay = new QVBoxLayout(page);
    page_vlay->setContentsMargins(0, 0, 0, 0);

#ifndef QT_NO_TOOLBAR
    mEditToolBar = new KToolBar(q);
    mEditToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
    page_vlay->addWidget(mEditToolBar, 0);

    mFormatToolBar = new KToolBar(q);
    mFormatToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
    page_vlay->addWidget(mFormatToolBar, 1);
#endif

    mTextEdit = new KPIMTextEdit::RichTextComposer(q);

    auto richTextEditorwidget = new TextCustomEditor::RichTextEditorWidget(mTextEdit, q);
    page_vlay->addWidget(richTextEditorwidget, 2);
    mTextEdit->setWhatsThis(i18n("Use this field to enter an arbitrary static signature."));

    // Fill the toolbars.
    auto actionCollection = new KActionCollection(q);
    mTextEdit->createActions(actionCollection);
#ifndef QT_NO_TOOLBAR
    mEditToolBar->addAction(actionCollection->action(QStringLiteral("format_text_bold")));
    mEditToolBar->addAction(actionCollection->action(QStringLiteral("format_text_italic")));
    mEditToolBar->addAction(actionCollection->action(QStringLiteral("format_text_underline")));
    mEditToolBar->addAction(actionCollection->action(QStringLiteral("format_text_strikeout")));
    mEditToolBar->addAction(actionCollection->action(QStringLiteral("format_text_foreground_color")));
    mEditToolBar->addAction(actionCollection->action(QStringLiteral("format_text_background_color")));
    mEditToolBar->addAction(actionCollection->action(QStringLiteral("format_font_family")));
    mEditToolBar->addAction(actionCollection->action(QStringLiteral("format_font_size")));
    mEditToolBar->addAction(actionCollection->action(QStringLiteral("format_reset")));

    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("format_list_style")));
    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("format_list_indent_more")));
    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("format_list_indent_less")));
    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("format_list_indent_less")));
    mFormatToolBar->addSeparator();

    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("format_align_left")));
    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("format_align_center")));
    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("format_align_right")));
    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("format_align_justify")));
    mFormatToolBar->addSeparator();

    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("insert_horizontal_rule")));
    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("manage_link")));
    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("format_painter")));

    mFormatToolBar->addSeparator();
    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("add_image")));
    mFormatToolBar->addSeparator();
    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("insert_html")));
    mFormatToolBar->addAction(actionCollection->action(QStringLiteral("insert_table")));
#endif

    hlay = new QHBoxLayout(); // inherits spacing
    page_vlay->addLayout(hlay);
    mHtmlCheck = new QCheckBox(i18n("&Use HTML"), page);
    q->connect(mHtmlCheck, &QCheckBox::clicked, q, &SignatureConfigurator::slotSetHtml);
    hlay->addWidget(mHtmlCheck);
    inlinedHtml = true;

    widgetStack->setCurrentIndex(0); // since mSourceCombo->currentItem() == 0
}

SignatureConfigurator::SignatureConfigurator(QWidget *parent)
    : QWidget(parent)
    , d(new SignatureConfiguratorPrivate(this))
{
    d->init();
}

SignatureConfigurator::~SignatureConfigurator() = default;

bool SignatureConfigurator::isSignatureEnabled() const
{
    return d->mEnableCheck->isChecked();
}

void SignatureConfigurator::setSignatureEnabled(bool enable)
{
    d->mEnableCheck->setChecked(enable);
}

Signature::Type SignatureConfigurator::signatureType() const
{
    return Signature::Inlined;
}

void SignatureConfigurator::setInlineText(const QString &text)
{
    d->mTextEdit->setTextOrHtml(text);
}

Signature SignatureConfigurator::signature() const
{
    Signature sig;
    const Signature::Type sigType = signatureType();
    switch (sigType) {
    case Signature::Inlined:
        sig.setInlinedHtml(d->inlinedHtml);
        sig.setText(d->inlinedHtml ? d->asCleanedHTML() : d->mTextEdit->textOrHtml());
        if (d->inlinedHtml) {
            if (!d->imageLocation.isEmpty()) {
                sig.setImageLocation(d->imageLocation);
            }
            const KPIMTextEdit::ImageWithNameList images = d->mTextEdit->composerControler()->composerImages()->imagesWithName();
            for (const KPIMTextEdit::ImageWithNamePtr &image : images) {
                sig.addImage(image->image, image->name);
            }
        }
        break;
    case Signature::Disabled:
        /* do nothing */
        break;
    }
    sig.setEnabledSignature(isSignatureEnabled());
    sig.setType(sigType);
    return sig;
}

void SignatureConfigurator::setSignature(const Signature &sig)
{
    setSignatureEnabled(sig.isEnabledSignature());

    if (sig.isInlinedHtml()) {
        d->mHtmlCheck->setCheckState(Qt::Checked);
    } else {
        d->mHtmlCheck->setCheckState(Qt::Unchecked);
    }
    slotSetHtml();

    // Let insertIntoTextEdit() handle setting the text, as that function also adds the images.
    d->mTextEdit->clear();
    SignatureRichTextEditor::insertIntoTextEdit(sig, Signature::Start, Signature::AddNothing, d->mTextEdit, true);
}

// "use HTML"-checkbox (un)checked
void SignatureConfigurator::slotSetHtml()
{
    if (d->mHtmlCheck->checkState() == Qt::Unchecked) {
        d->mHtmlCheck->setText(i18n("&Use HTML"));
#ifndef QT_NO_TOOLBAR
        d->mEditToolBar->setVisible(false);
        d->mEditToolBar->setEnabled(false);
        d->mFormatToolBar->setVisible(false);
        d->mFormatToolBar->setEnabled(false);
#endif
        d->mTextEdit->switchToPlainText();
        d->inlinedHtml = false;
    } else {
        d->mHtmlCheck->setText(i18n("&Use HTML (disabling removes formatting)"));
        d->inlinedHtml = true;
#ifndef QT_NO_TOOLBAR
        d->mEditToolBar->setVisible(true);
        d->mEditToolBar->setEnabled(true);
        d->mFormatToolBar->setVisible(true);
        d->mFormatToolBar->setEnabled(true);
#endif
        d->mTextEdit->activateRichText();
    }
}

void SignatureConfigurator::setImageLocation(const QString &path)
{
    d->imageLocation = path;
}

void SignatureConfigurator::setImageLocation(const KIdentityManagementCore::Identity &identity)
{
    const QString dir =
        QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/emailidentities/%1/").arg(QString::number(identity.uoid()));
    QDir().mkpath(dir);
    setImageLocation(dir);
}
}

#include "moc_signatureconfigurator.cpp"
