/* ============================================================
 *
 * This file is a part of digiKam project
 * https://www.digikam.org
 *
 * Date        : 2009-02-28
 * Description : batch tool to add visible watermark.
 *
 * Copyright (C) 2009-2022 by Gilles Caulier <caulier dot gilles at gmail dot com>
 * Copyright (C) 2010      by Mikkel Baekhoej Christensen <mbc at baekhoej dot dk>
 * Copyright (C) 2017      by Ahmed Fathi <ahmed dot fathi dot abdelmageed at gmail dot 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 2, 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.
 *
 * ============================================================ */

#include "watermark.h"

// Qt includes

#include <QFontMetrics>
#include <QLabel>
#include <QPainter>
#include <QPen>
#include <QPoint>
#include <QRect>
#include <QWidget>
#include <QGridLayout>
#include <QRadioButton>
#include <QCheckBox>
#include <QGroupBox>
#include <QApplication>
#include <QStyle>
#include <QFontComboBox>
#include <QComboBox>
#include <QLineEdit>
#include <QDoubleSpinBox>

// KDE includes

#include <klocalizedstring.h>

// Local includes

#include "dlayoutbox.h"
#include "dnuminput.h"
#include "dfileselector.h"
#include "digikam_debug.h"
#include "dimg.h"
#include "blurfilter.h"
#include "dfontproperties.h"
#include "metaengine.h"
#include "dcolorselector.h"

namespace DigikamBqmWatermarkPlugin
{

class Q_DECL_HIDDEN WaterMark::Private
{

public:

    enum WaterMarkPositon
    {
        TopLeft = 0,
        TopRight,
        BottomLeft,
        BottomRight,
        Center
    };

    enum WaterMarkPlacementType
    {
        SpecifiedLocation = 0,
        SystematicRepetition,
        RandomRepetition
    };

public:

    explicit Private()
      : textSettingsGroupBox                      (nullptr),
        imageSettingsGroupBox                     (nullptr),
        useAbsoluteImageSizeGroupBox              (nullptr),
        useImageRadioButton                       (nullptr),
        ignoreWatermarkAspectCheckBox             (nullptr),
        addTransparencyToWatermarkImageCheckBox   (nullptr),
        useAbsoluteSizeCheckBox                   (nullptr),
        useBackgroundCheckBox                     (nullptr),
        denseRepetitionCheckBox                   (nullptr),
        randomizeRotationCheckBox                 (nullptr),
        useTextRadioButton                        (nullptr),
        imageFileUrlRequester                     (nullptr),
        textEdit                                  (nullptr),
        placementPositionComboBox                 (nullptr),
        placementTypeComboBox                     (nullptr),
        rotationComboBox                          (nullptr),
        sparsityFactorSpinBox                     (nullptr),
        extendedFontChooserWidget                 (nullptr),
        fontColorButton                           (nullptr),
        backgroundColorButton                     (nullptr),
        textOpacity                               (nullptr),
        backgroundOpacity                         (nullptr),
        xMarginInput                              (nullptr),
        yMarginInput                              (nullptr),
        waterMarkSizePercent                      (nullptr),
        waterMarkOpacityPercent                   (nullptr),
        changeSettings                            (true)
    {
    }

    QGroupBox*       textSettingsGroupBox;
    QGroupBox*       imageSettingsGroupBox;
    QGroupBox*       useAbsoluteImageSizeGroupBox ;
    QRadioButton*    useImageRadioButton;
    QCheckBox*       ignoreWatermarkAspectCheckBox;
    QCheckBox*       addTransparencyToWatermarkImageCheckBox;
    QCheckBox*       useAbsoluteSizeCheckBox;
    QCheckBox*       useBackgroundCheckBox;
    QCheckBox*       denseRepetitionCheckBox;
    QCheckBox*       randomizeRotationCheckBox;
    QRadioButton*    useTextRadioButton;

    DFileSelector*   imageFileUrlRequester;
    QLineEdit*       textEdit;

    QComboBox*       placementPositionComboBox;
    QComboBox*       placementTypeComboBox;
    QComboBox*       rotationComboBox;
    QDoubleSpinBox*  sparsityFactorSpinBox;
    DFontProperties* extendedFontChooserWidget;

    DColorSelector*  fontColorButton;
    DColorSelector*  backgroundColorButton;

    DIntNumInput*    textOpacity;
    DIntNumInput*    backgroundOpacity;
    DIntNumInput*    xMarginInput;
    DIntNumInput*    yMarginInput;
    DIntNumInput*    waterMarkSizePercent;
    DIntNumInput*    waterMarkOpacityPercent;

    bool             changeSettings;
};

WaterMark::WaterMark(QObject* const parent)
    : BatchTool(QLatin1String("WaterMark"), DecorateTool, parent),
      d        (new Private)
{
}

WaterMark::~WaterMark()
{
    delete d;
}

BatchTool* WaterMark::clone(QObject* const parent) const
{
    return new WaterMark(parent);
}

void WaterMark::registerSettingsWidget()
{
    const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);

    DVBox* const vbox = new DVBox;
    vbox->setContentsMargins(QMargins());
    vbox->setSpacing(spacing);

    DHBox* const hbox = new DHBox(vbox);
    hbox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    hbox->setSpacing(10);

    d->useAbsoluteImageSizeGroupBox                       = new QGroupBox(vbox);
    QVBoxLayout* const useAbsoluteImageSizeGroupBoxLayout = new QVBoxLayout;
    useAbsoluteImageSizeGroupBoxLayout->setContentsMargins(spacing, spacing, spacing, spacing);
    useAbsoluteImageSizeGroupBoxLayout->addStretch(1);
    d->useAbsoluteImageSizeGroupBox->setLayout(useAbsoluteImageSizeGroupBoxLayout);

    DHBox* const useAbsoluteSizeHBox   = new DHBox();
    useAbsoluteSizeHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    useAbsoluteSizeHBox->setSpacing(10);
    d->useAbsoluteSizeCheckBox         = new QCheckBox(useAbsoluteSizeHBox);
    d->useAbsoluteSizeCheckBox->setWhatsThis(i18n("Check this if you want the watermark to use the given size of "
                                                  "the font or the image without any adjustment to the actual image."));
    QLabel* const useAbsoluteSizeLabel = new QLabel(useAbsoluteSizeHBox);
    useAbsoluteSizeLabel->setText(i18n("Use Absolute Size"));
    d->useAbsoluteSizeCheckBox->setChecked(false);

    useAbsoluteImageSizeGroupBoxLayout->addWidget(useAbsoluteSizeHBox);

    QLabel* const watermarkTypeLabel   = new QLabel(hbox);
    watermarkTypeLabel->setText(i18n("Watermark type:"));

    d->useImageRadioButton      = new QRadioButton(hbox);
    d->useImageRadioButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    QLabel* const useImageLabel = new QLabel(hbox);
    useImageLabel ->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    d->useTextRadioButton       = new QRadioButton(hbox);
    d->useTextRadioButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    QLabel* const useTextLabel  = new QLabel(hbox);
    useTextLabel ->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    useImageLabel->setText(i18n("Image"));
    useTextLabel->setText(i18n("Text"));

    useImageLabel->setAlignment(Qt::AlignLeft);
    useTextLabel->setAlignment(Qt::AlignLeft);
    d->useImageRadioButton->setChecked(true);

    d->imageSettingsGroupBox                       = new QGroupBox(vbox);
    d->imageSettingsGroupBox->setTitle(i18n("Image settings"));
    QVBoxLayout* const imageSettingsGroupBoxLayout = new QVBoxLayout;
    imageSettingsGroupBoxLayout->setContentsMargins(spacing, spacing, spacing, spacing);
    imageSettingsGroupBoxLayout->addStretch(1);
    d->imageSettingsGroupBox->setLayout(imageSettingsGroupBoxLayout);

    QLabel* const label      = new QLabel();
    d->imageFileUrlRequester = new DFileSelector();
    d->imageFileUrlRequester->lineEdit()->setPlaceholderText(i18n("Click to select watermark image."));
    label->setText(i18n("Watermark image:"));
    imageSettingsGroupBoxLayout->addWidget(label);
    imageSettingsGroupBoxLayout->addWidget(d->imageFileUrlRequester);

    DHBox* const ignoreWatermarkAspectRatioHBox   = new DHBox();
    ignoreWatermarkAspectRatioHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    ignoreWatermarkAspectRatioHBox->setSpacing(5);

    d->ignoreWatermarkAspectCheckBox              = new QCheckBox(ignoreWatermarkAspectRatioHBox);
    d->ignoreWatermarkAspectCheckBox->setWhatsThis(i18n("Check this if you want the watermark to ignore its own "
                                                        "aspect ratio and use the image's aspect ratio instead."));

    QLabel* const ignoreWatermarkAspectRatioLabel = new QLabel(ignoreWatermarkAspectRatioHBox);
    ignoreWatermarkAspectRatioLabel->setText(i18n("Ignore Watermark aspect Ratio"));
    d->ignoreWatermarkAspectCheckBox->setChecked(false);
    imageSettingsGroupBoxLayout->addWidget(ignoreWatermarkAspectRatioHBox);

    DHBox* const addTransparencyToWatermarkImageHBox = new DHBox();
    addTransparencyToWatermarkImageHBox->setContentsMargins(QMargins());
    addTransparencyToWatermarkImageHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    addTransparencyToWatermarkImageHBox->setSpacing(5);

    d->addTransparencyToWatermarkImageCheckBox       = new QCheckBox(addTransparencyToWatermarkImageHBox);
    d->addTransparencyToWatermarkImageCheckBox->setWhatsThis(i18n("Check this if you want watermark to be transparent."));
    d->addTransparencyToWatermarkImageCheckBox->setChecked(false);

    QLabel* const addTransparencyToWatermarkLabel    = new QLabel(addTransparencyToWatermarkImageHBox);
    addTransparencyToWatermarkLabel->setText(i18n("Add transparency to watermark image"));
    imageSettingsGroupBoxLayout->addWidget(addTransparencyToWatermarkImageHBox);

    DVBox* const watermarkImageOpacityBox = new DVBox();
    watermarkImageOpacityBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    watermarkImageOpacityBox->setSpacing(5);

    QLabel* const opacityLabel            = new QLabel(watermarkImageOpacityBox);
    d->waterMarkOpacityPercent            = new DIntNumInput(watermarkImageOpacityBox);
    d->waterMarkOpacityPercent->setRange(0, 100, 1);
    d->waterMarkOpacityPercent->setDefaultValue(100);
    d->waterMarkOpacityPercent->setWhatsThis(i18n("Opacity of watermark"));
    opacityLabel->setText(i18n("Opacity (%):"));
    imageSettingsGroupBoxLayout->addWidget(watermarkImageOpacityBox);
 
    d->textSettingsGroupBox                       = new QGroupBox(vbox);
    d->textSettingsGroupBox->setTitle(i18n("Text settings"));
    QVBoxLayout* const textSettingsGroupBoxLayout = new QVBoxLayout;
    textSettingsGroupBoxLayout->setContentsMargins(spacing, spacing, spacing, spacing);
    textSettingsGroupBoxLayout->addStretch(1);
    d->textSettingsGroupBox->setLayout(textSettingsGroupBoxLayout);

    QLabel* const textEditLabel = new QLabel(vbox);
    d->textEdit                 = new QLineEdit(vbox);
    d->textEdit->setClearButtonEnabled(true);
    d->textEdit->setPlaceholderText(i18n("Enter your watermark string here."));
    textEditLabel->setText(i18n("Watermark text:"));
    textSettingsGroupBoxLayout->addWidget(textEditLabel);
    textSettingsGroupBoxLayout->addWidget(d->textEdit);

    d->extendedFontChooserWidget = new DFontProperties(nullptr, DFontProperties::NoDisplayFlags);
    d->extendedFontChooserWidget->setSampleBoxVisible(true);
    d->extendedFontChooserWidget->enableColumn(0x04, false);
    d->extendedFontChooserWidget->setWhatsThis(i18n("Choose the font type and style. Size is auto calculated."));
    textSettingsGroupBoxLayout->addWidget(d->extendedFontChooserWidget);

    QLabel* const label3 = new QLabel();
    d->fontColorButton   = new DColorSelector();
    d->fontColorButton->setColor(Qt::black);
    d->fontColorButton->setWhatsThis(i18n("Set the font color to use here."));
    label3->setText(i18n("Font color:"));
    textSettingsGroupBoxLayout->addWidget(label3);
    textSettingsGroupBoxLayout->addWidget(d->fontColorButton);

    QLabel* const textOpacityLabel = new QLabel();
    textOpacityLabel->setText(i18n("Text opacity:"));
    d->textOpacity                 = new DIntNumInput();
    d->textOpacity->setRange(0, 100, 1);
    d->textOpacity->setDefaultValue(100);
    d->textOpacity->setWhatsThis(i18n("Set the opacity of the watermark text. "
                                      "100 is fully opaque, 0 is fully transparent."));
    textSettingsGroupBoxLayout->addWidget(textOpacityLabel);
    textSettingsGroupBoxLayout->addWidget(d->textOpacity);

    DHBox* const useBackgroundHBox   = new DHBox();
    useBackgroundHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    useBackgroundHBox->setSpacing(5);

    d->useBackgroundCheckBox         = new QCheckBox(useBackgroundHBox);
    d->useBackgroundCheckBox->setWhatsThis(i18n("Check this if you want a background fill behind the text."));
    QLabel* const useBackgroundLabel = new QLabel(useBackgroundHBox);
    useBackgroundLabel->setText(i18n("Use background"));
    textSettingsGroupBoxLayout->addWidget(useBackgroundHBox);

    QLabel* const backgroundColorLabel = new QLabel();
    d->backgroundColorButton           = new DColorSelector();
    d->backgroundColorButton->setColor(QColor(0xCC, 0xCC, 0xCC));
    d->backgroundColorButton->setWhatsThis(i18n("Choose the color of the watermark background."));
    backgroundColorLabel ->setText(i18n("Background color:"));
    textSettingsGroupBoxLayout->addWidget(backgroundColorLabel);
    textSettingsGroupBoxLayout->addWidget(d->backgroundColorButton);

    QLabel* const backgroundOpacityLabel = new QLabel();
    backgroundOpacityLabel->setText(i18n("Background opacity:"));
    d->backgroundOpacity                 = new DIntNumInput();
    d->backgroundOpacity->setRange(0, 100, 1);
    d->backgroundOpacity->setDefaultValue(100);
    d->backgroundOpacity->setWhatsThis(i18n("Set the opacity of the watermark background. "
                                            "100 is fully opaque, 0 is fully transparent."));
    textSettingsGroupBoxLayout->addWidget(backgroundOpacityLabel);
    textSettingsGroupBoxLayout->addWidget(d->backgroundOpacity);

    d->imageSettingsGroupBox->setVisible(true);
    d->textSettingsGroupBox->setVisible(false);

    QLabel* const placementTypeLabel = new QLabel(vbox);
    d->placementTypeComboBox         = new QComboBox(vbox);
    d->placementTypeComboBox->insertItem(Private::SpecifiedLocation,    i18n("Specific Location"));
    d->placementTypeComboBox->insertItem(Private::SystematicRepetition, i18n("Systematic Repetition"));
    d->placementTypeComboBox->insertItem(Private::RandomRepetition,     i18n("Random Repetition"));
    placementTypeLabel->setText(i18n("Placement Type:"));

    DHBox* const placementHBox = new DHBox(vbox);
    placementHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    placementHBox->setSpacing(5);

    QLabel* const spaceLabel   = new QLabel(placementHBox);
    d->denseRepetitionCheckBox = new QCheckBox(placementHBox);
    d->denseRepetitionCheckBox->setWhatsThis(i18n("When you choose to have the watermark repeated many times in the "
                                                  "placement combo box, you can specify here whether the repetition."));
    d->denseRepetitionCheckBox->setChecked(false);
    d->denseRepetitionCheckBox->setEnabled(false);
    spaceLabel->setText(QLatin1String(" "));
    QLabel* const placementDensityLabel = new QLabel(placementHBox);
    placementDensityLabel->setText(i18n("Density of watermark repetition (Disabled in \"Specific Location\" mode)"));

    DHBox* const randomizeHBox          = new DHBox(vbox);
    randomizeHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    randomizeHBox->setSpacing(5);

    QLabel* const spaceLabel2           = new QLabel(randomizeHBox);
    d->randomizeRotationCheckBox        = new QCheckBox(randomizeHBox);
    d->randomizeRotationCheckBox->setWhatsThis(i18n("When you choose to have the watermark repeated randomly in "
                                                    "the placement combo box, you can specify here to randomly "
                                                    "rotate the watermark (0, 90, 180, 270 degrees)."));
    d->randomizeRotationCheckBox->setChecked(true);
    d->denseRepetitionCheckBox->setEnabled(false);
    spaceLabel2->setText(QLatin1String(" "));
    QLabel* const randomizeRotation   = new QLabel(randomizeHBox);
    randomizeRotation->setText(i18n("Randomize watermark orientation (Enabled in \"Random Repetition\" mode only)"));

    DHBox* const sparsityHBox         = new DHBox(vbox);
    sparsityHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    sparsityHBox->setSpacing(5);

    QLabel* const sparsityFactorLabel = new QLabel(sparsityHBox);
    d->sparsityFactorSpinBox          = new QDoubleSpinBox(sparsityHBox);
    d->sparsityFactorSpinBox->setMinimum(0.0);
    d->sparsityFactorSpinBox->setValue(1);
    d->sparsityFactorSpinBox->setSingleStep(0.1);
    d->sparsityFactorSpinBox->setWhatsThis(i18n("Use this to get more control over the sparsity of watermark "
                                           "repetition. The higher the value the sparser the watermarks get. "
                                           "Use floating point values, typically between 1.0 and 3.0. It can "
                                           "also be less than 1.0"));
    sparsityFactorLabel->setText(i18n("Sparsity Factor:"));

    QLabel* const label4         = new QLabel(vbox);
    d->placementPositionComboBox = new QComboBox(vbox);
    d->placementPositionComboBox->insertItem(Private::TopLeft,     i18nc("@item: placement position", "Top left"));
    d->placementPositionComboBox->insertItem(Private::TopRight,    i18nc("@item: placement position", "Top right"));
    d->placementPositionComboBox->insertItem(Private::BottomLeft,  i18nc("@item: placement position", "Bottom left"));
    d->placementPositionComboBox->insertItem(Private::BottomRight, i18nc("@item: placement position", "Bottom right"));
    d->placementPositionComboBox->insertItem(Private::Center,      i18nc("@item: placement position", "Center"));
    label4->setText(i18n("Placement Position:"));

    QLabel* const labelRotation  = new QLabel(vbox);
    d->rotationComboBox          = new QComboBox(vbox);
    d->rotationComboBox->insertItem(0, i18n("0 degrees"));
    d->rotationComboBox->insertItem(1, i18n("90 degrees CW"));
    d->rotationComboBox->insertItem(2, i18n("180 degrees"));
    d->rotationComboBox->insertItem(3, i18n("270 degrees CW"));
    labelRotation->setText(i18n("Rotation:"));

    QLabel* const label5    = new QLabel(vbox);
    d->waterMarkSizePercent = new DIntNumInput(vbox);
    d->waterMarkSizePercent->setRange(0, 100, 1);
    d->waterMarkSizePercent->setDefaultValue(30);
    d->waterMarkSizePercent->setWhatsThis(i18n("Size of watermark, as a percentage of the marked image."));
    label5->setText(i18n("Size (%):"));

    QLabel* const label6 = new QLabel(vbox);
    d->xMarginInput      = new DIntNumInput(vbox);
    d->xMarginInput->setRange(0, 100, 1);
    d->xMarginInput->setDefaultValue(2);
    d->xMarginInput->setWhatsThis(i18n("Margin from edge in X direction, as a percentage of the marked image."));
    label6->setText(i18n("X margin (%):"));

    QLabel* const label7 = new QLabel(vbox);
    d->yMarginInput      = new DIntNumInput(vbox);
    d->yMarginInput->setRange(0, 100, 1);
    d->yMarginInput->setDefaultValue(2);
    d->yMarginInput->setWhatsThis(i18n("Margin from edge in Y direction, as a percentage of the marked image."));
    label7->setText(i18n("Y margin (%):"));

    QLabel* const space = new QLabel(vbox);
    vbox->setStretchFactor(space, 10);

    m_settingsWidget    = vbox;

    // ------------------------------------------------------------------------------------------------------

    connect(d->useImageRadioButton, SIGNAL(toggled(bool)),
            this, SLOT(slotSettingsChanged()));

    connect(d->useTextRadioButton, SIGNAL(toggled(bool)),
            this, SLOT(slotSettingsChanged()));

    connect(d->imageFileUrlRequester->lineEdit(), SIGNAL(textChanged(QString)),
            this, SLOT(slotSettingsChanged()));

    connect(d->extendedFontChooserWidget, SIGNAL(fontSelected(QFont)),
            this, SLOT(slotSettingsChanged()));

    connect(d->fontColorButton, SIGNAL(signalColorSelected(QColor)),
            this, SLOT(slotSettingsChanged()));

    connect(d->textEdit, SIGNAL(textChanged(QString)),
            this, SLOT(slotSettingsChanged()));

    connect(d->textOpacity, SIGNAL(valueChanged(int)),
            this, SLOT(slotSettingsChanged()));

    connect(d->useBackgroundCheckBox, SIGNAL(toggled(bool)),
            this, SLOT(slotSettingsChanged()));

    connect(d->ignoreWatermarkAspectCheckBox, SIGNAL(toggled(bool)),
            this, SLOT(slotSettingsChanged()));

    connect(d->addTransparencyToWatermarkImageCheckBox, SIGNAL(toggled(bool)),
            this, SLOT(slotSettingsChanged()));

    connect(d->useAbsoluteSizeCheckBox, SIGNAL(toggled(bool)),
            this, SLOT(slotSettingsChanged()));

    connect(d->backgroundColorButton, SIGNAL(signalColorSelected(QColor)),
            this, SLOT(slotSettingsChanged()));

    connect(d->backgroundOpacity, SIGNAL(valueChanged(int)),
            this, SLOT(slotSettingsChanged()));

    connect(d->placementTypeComboBox, SIGNAL(activated(int)),
            this, SLOT(slotSettingsChanged()));

    connect(d->placementPositionComboBox, SIGNAL(activated(int)),
            this, SLOT(slotSettingsChanged()));

    connect(d->denseRepetitionCheckBox, SIGNAL(toggled(bool)),
            this, SLOT(slotSettingsChanged()));

    connect(d->randomizeRotationCheckBox, SIGNAL(toggled(bool)),
            this, SLOT(slotSettingsChanged()));

    connect(d->sparsityFactorSpinBox, SIGNAL(valueChanged(double)),
            this, SLOT(slotSettingsChanged()));

    connect(d->rotationComboBox, SIGNAL(activated(int)),
            this, SLOT(slotSettingsChanged()));

    connect(d->waterMarkSizePercent, SIGNAL(valueChanged(int)),
            this, SLOT(slotSettingsChanged()));

    connect(d->yMarginInput, SIGNAL(valueChanged(int)),
            this, SLOT(slotSettingsChanged()));

    connect(d->xMarginInput, SIGNAL(valueChanged(int)),
            this, SLOT(slotSettingsChanged()));

    connect(d->waterMarkOpacityPercent, SIGNAL(valueChanged(int)),
	    this, SLOT(slotSettingsChanged()));

    BatchTool::registerSettingsWidget();
}

BatchToolSettings WaterMark::defaultSettings()
{
    BatchToolSettings settings;

    settings.insert(QLatin1String("Use image"),          true);
    settings.insert(QLatin1String("Watermark image"),    QString());
    settings.insert(QLatin1String("Text"),               QString());
    settings.insert(QLatin1String("Font"),               QFont());
    settings.insert(QLatin1String("Color"),              QColor(Qt::black));
    settings.insert(QLatin1String("Text opacity"),       100);
    settings.insert(QLatin1String("Use background"),     true);
    settings.insert(QLatin1String("Background color"),   QColor(0xCC, 0xCC, 0xCC));
    settings.insert(QLatin1String("Background opacity"), 0xCC);
    settings.insert(QLatin1String("PlacementType"),      Private::SpecifiedLocation); // specified location for the watermark
    settings.insert(QLatin1String("Dense Repetition"),   false);
    settings.insert(QLatin1String("Randomize Rotation"), true);
    settings.insert(QLatin1String("Sparsity Factor"),    1.0);
    settings.insert(QLatin1String("Placement"),          Private::BottomRight);
    settings.insert(QLatin1String("Rotation"),           0);
    settings.insert(QLatin1String("Watermark size"),     25);
    settings.insert(QLatin1String("X margin"),           2);
    settings.insert(QLatin1String("Y margin"),           2);
    settings.insert(QLatin1String("Opacity"),            100);

    return settings;
}

void WaterMark::slotAssignSettings2Widget()
{
    d->changeSettings = false;
    d->useImageRadioButton->setChecked(settings()[QLatin1String("Use image")].toBool());
    d->useTextRadioButton->setChecked(!settings()[QLatin1String("Use image")].toBool());
    d->imageFileUrlRequester->setFileDlgPath(settings()[QLatin1String("Watermark image")].toString());
    d->textEdit->setText(settings()[QLatin1String("Text")].toString());
    d->extendedFontChooserWidget->setFont(qvariant_cast<QFont>(settings()[QLatin1String("Font")]));
    d->fontColorButton->setColor(settings()[QLatin1String("Color")].toString());
    d->textOpacity->setValue(settings()[QLatin1String("Text opacity")].toInt());
    d->useBackgroundCheckBox->setChecked(settings()[QLatin1String("Use background")].toBool());
    d->backgroundColorButton->setColor(settings()[QLatin1String("Background color")].toString());
    d->backgroundOpacity->setValue(settings()[QLatin1String("Background opacity")].toInt());
    d->placementPositionComboBox->setCurrentIndex(settings()[QLatin1String("PlacementType")].toInt());
    d->denseRepetitionCheckBox->setChecked(settings()[QLatin1String("Dense Repetition")].toBool());
    d->randomizeRotationCheckBox->setChecked(settings()[QLatin1String("Randomize Rotation")].toBool());
    d->sparsityFactorSpinBox->setValue(settings()[QLatin1String("Sparsity Factor")].toDouble());
    d->placementPositionComboBox->setCurrentIndex(settings()[QLatin1String("Placement")].toInt());
    d->rotationComboBox->setCurrentIndex(settings()[QLatin1String("Rotation")].toInt());
    d->waterMarkSizePercent->setValue(settings()[QLatin1String("Watermark size")].toInt());
    d->xMarginInput->setValue(settings()[QLatin1String("X margin")].toInt());
    d->yMarginInput->setValue(settings()[QLatin1String("Y margin")].toInt());
    d->waterMarkOpacityPercent->setValue(settings()[QLatin1String("Opacity")].toInt());
    d->changeSettings = true;
}

void WaterMark::slotSettingsChanged()
{
    if      (d->useImageRadioButton->isChecked())
    {
        d->textSettingsGroupBox->setVisible(false);
        d->imageSettingsGroupBox->setVisible(true);
    }
    else if (d->useTextRadioButton->isChecked())
    {
        d->imageSettingsGroupBox->setVisible(false);
        d->textSettingsGroupBox->setVisible(true);
    }

    d->waterMarkSizePercent->setEnabled(!d->useAbsoluteSizeCheckBox->isChecked());
    d->extendedFontChooserWidget->enableColumn(0x04, d->useAbsoluteSizeCheckBox->isChecked());
    d->placementPositionComboBox->setEnabled(((int)d->placementTypeComboBox->currentIndex() == Private::SpecifiedLocation));
    d->denseRepetitionCheckBox->setEnabled(((int)d->placementTypeComboBox->currentIndex() != Private::SpecifiedLocation));
    d->sparsityFactorSpinBox->setEnabled(((int)d->placementTypeComboBox->currentIndex() != Private::SpecifiedLocation));
    d->randomizeRotationCheckBox->setEnabled(((int)d->placementTypeComboBox->currentIndex() == Private::RandomRepetition));
    d->rotationComboBox->setEnabled(!(d->randomizeRotationCheckBox->isEnabled() && d->randomizeRotationCheckBox->isChecked()));
    d->waterMarkOpacityPercent->setEnabled(d->addTransparencyToWatermarkImageCheckBox->isChecked());

    if (d->changeSettings)
    {
        BatchToolSettings settings;
        settings.insert(QLatin1String("Use image"),                     d->useImageRadioButton->isChecked());
        settings.insert(QLatin1String("Watermark image"),               d->imageFileUrlRequester->fileDlgPath());
        settings.insert(QLatin1String("Text"),                          d->textEdit->text());
        settings.insert(QLatin1String("Font"),                          d->extendedFontChooserWidget->font());
        settings.insert(QLatin1String("Color"),                         d->fontColorButton->color());
        settings.insert(QLatin1String("Text opacity"),                  d->textOpacity->value());
        settings.insert(QLatin1String("Use background"),                d->useBackgroundCheckBox->isChecked());
        settings.insert(QLatin1String("Ignore Watermark Aspect Ratio"), d->ignoreWatermarkAspectCheckBox->isChecked());
        settings.insert(QLatin1String("Use Absolute Size"),             d->useAbsoluteSizeCheckBox->isChecked());
        settings.insert(QLatin1String("Background color"),              d->backgroundColorButton->color());
        settings.insert(QLatin1String("Background opacity"),            d->backgroundOpacity->value());
        settings.insert(QLatin1String("Dense Repetition"),              d->denseRepetitionCheckBox->isChecked());
        settings.insert(QLatin1String("Randomize Rotation"),            d->randomizeRotationCheckBox->isChecked());
        settings.insert(QLatin1String("Sparsity Factor"),               (double)d->sparsityFactorSpinBox->value());
        settings.insert(QLatin1String("PlacementType"),                 (int)d->placementTypeComboBox->currentIndex());
        settings.insert(QLatin1String("Placement"),                     (int)d->placementPositionComboBox->currentIndex());
        settings.insert(QLatin1String("Rotation"),                      (int)d->rotationComboBox->currentIndex());
        settings.insert(QLatin1String("Watermark size"),                (int)d->waterMarkSizePercent->value());
        settings.insert(QLatin1String("X margin"),                      (int)d->xMarginInput->value());
        settings.insert(QLatin1String("Y margin"),                      (int)d->yMarginInput->value());
        settings.insert(QLatin1String("Opacity"),                       (int)d->waterMarkOpacityPercent->value());
        settings.insert(QLatin1String("Add transparency"),              d->addTransparencyToWatermarkImageCheckBox->isChecked());
        BatchTool::slotSettingsChanged(settings);
    }
}

bool WaterMark::toolOperations()
{
    if (!loadToDImg())
    {
        return false;
    }

    QString fileName                             = settings()[QLatin1String("Watermark image")].toString();
    int placementPosition                        = settings()[QLatin1String("Placement")].toInt();
    int placementType                            = settings()[QLatin1String("PlacementType")].toInt();
    bool denseRepetition                         = settings()[QLatin1String("Dense Repetition")].toBool();
    bool randomizeRotation                       = settings()[QLatin1String("Randomize Rotation")].toBool();
    double userSparsityFactor                    = settings()[QLatin1String("Sparsity Factor")].toDouble();
    int size                                     = settings()[QLatin1String("Watermark size")].toInt();
    int xMargin                                  = settings()[QLatin1String("X margin")].toInt();
    int yMargin                                  = settings()[QLatin1String("Y margin")].toInt();
    bool useImage                                = settings()[QLatin1String("Use image")].toBool();
    QString text                                 = settings()[QLatin1String("Text")].toString();
    QFont font                                   = qvariant_cast<QFont>(settings()[QLatin1String("Font")]);

    QColor fontColor                             = settings()[QLatin1String("Color")].toString();
    int textOpacity                              = settings()[QLatin1String("Text opacity")].toInt();
    bool useBackground                           = settings()[QLatin1String("Use background")].toBool();
    QColor backgroundColor                       = settings()[QLatin1String("Background color")].toString();
    int backgroundOpacity                        = settings()[QLatin1String("Background opacity")].toInt();
    Qt::AspectRatioMode watermarkAspectRatioMode = settings()[QLatin1String("Ignore Watermark Aspect Ratio")].toBool() ?
                                                              Qt::IgnoreAspectRatio : Qt::KeepAspectRatio;
    bool useAbsoluteSize                         = settings()[QLatin1String("Use Absolute Size")].toBool();

    DImg watermarkImage;
    DColorComposer* const composer               = DColorComposer::getComposer(DColorComposer::PorterDuffNone);
    int marginW                                  = lround(image().width()  * (xMargin / 100.0));
    int marginH                                  = lround(image().height() * (yMargin / 100.0));
    int rotationIndex = settings()[QLatin1String("Rotation")].toInt();
    double opacity                               = settings()[QLatin1String("Opacity")].toInt()/100.0;
    bool addTransparency                         = settings()[QLatin1String("Add transparency")].toBool();

    DImg::ANGLE rotationAngle = (rotationIndex == 1) ? DImg::ANGLE::ROT90 :
                                (rotationIndex == 2) ? DImg::ANGLE::ROT180 :
                                (rotationIndex == 3) ? DImg::ANGLE::ROT270 :
                                                       DImg::ANGLE::ROTNONE;

    // rotate and/or flip the image depending on the exif information to allow for the expected watermark placement.
    // note that this operation is reversed after proper watermark generation to leave everything as it was.

    image().exifRotate(inputUrl().toLocalFile());

    float ratio = (float)image().height() / image().width();

    if ((rotationAngle == DImg::ANGLE::ROT90) || (rotationAngle == DImg::ANGLE::ROT270))
    {
        size = size * ratio;
    }
    else
    {
        // For Images whose height are much larger than their width, this helps keep
        // the watermark size reasonable

        if (ratio > 1.5)
        {
            int tempSize  = size * ratio;

            if (tempSize < 35)
            {
                tempSize *= 1.5;
            }

            size          = (tempSize < 100) ? tempSize : 100;
        }
    }

    if (useImage)
    {
        watermarkImage = DImg(fileName);

        if (watermarkImage.isNull())
        {
            return false;
        }

        if (!useAbsoluteSize)
        {
            DImg tempImage = watermarkImage.smoothScale(image().width()  * size / 100,
                                                        image().height() * size / 100,
                                                        watermarkAspectRatioMode);
            watermarkImage = tempImage;
        }

        if (addTransparency)
        {
            if (!watermarkImage.hasAlpha())
            {
                return false;
            }

            for (uint i = 0 ; i < watermarkImage.width() ; ++i)
            {
                for (uint j = 0 ; j < watermarkImage.height() ; ++j)
                {
                    DColor color = watermarkImage.getPixelColor(i, j);
                    color.setAlpha((int)(opacity*color.alpha()));
                    watermarkImage.setPixelColor(i, j, color);
                }
            }
        }
    }
    else
    {
        int alignMode;
        const int radius = 10;

        if (text.isEmpty())
        {
            return false;
        }

        int fontSize = queryFontSize(text, font, size);

        if (fontSize == 0)
        {
            return false;
        }

        switch (placementPosition)
        {
            case Private::TopLeft:
            {
                alignMode = Qt::AlignLeft;
                break;
            }

            case Private::TopRight:
            {
                alignMode = Qt::AlignRight;
                break;
            }

            case Private::BottomLeft:
            {
                alignMode = Qt::AlignLeft;
                break;
            }

            case Private::Center:
            {
                alignMode = Qt::AlignCenter;
                break;
            }

            default:    // BottomRight
            {
                alignMode = Qt::AlignRight;
                break;
            }
        }

        if (!useAbsoluteSize)
        {
            font.setPointSizeF(fontSize);
        }

        QFontMetrics fontMt(font);
        QRect fontRect = fontMt.boundingRect(radius, radius, image().width(), image().height(), 0, text);

        // Add a transparent layer.

        QRect backgroundRect(fontRect.x() - radius, fontRect.y() - radius,
                             fontRect.width() + 2 * radius, fontRect.height() + 2 * radius);
        DImg backgroundLayer(backgroundRect.width(), backgroundRect.height(), image().sixteenBit(), true);
        DColor transparent(QColor(0, 0, 0));
        transparent.setAlpha(0);

        if (image().sixteenBit())
        {
            transparent.convertToSixteenBit();
        }

        backgroundLayer.fill(transparent);

        DImg grayTransLayer(fontRect.width(), fontRect.height(), image().sixteenBit(), true);

        if (useBackground)
        {
            DColor grayTrans(backgroundColor);
            grayTrans.setAlpha(backgroundOpacity * 255 / 100);

            if (image().sixteenBit())
            {
                grayTrans.convertToSixteenBit();
            }

            grayTransLayer.fill(grayTrans);
            backgroundLayer.bitBlendImage(composer, &grayTransLayer, 0, 0,
                                          grayTransLayer.width(), grayTransLayer.height(),
                                          radius, radius);
        }

        BlurFilter blur(&backgroundLayer, nullptr, radius);
        blur.startFilterDirectly();
        backgroundLayer.putImageData(blur.getTargetImage().bits());

        // Draw text

        QImage img = backgroundLayer.copyQImage(fontRect);
        QPainter p(&img);
        fontColor.setAlpha(textOpacity * 255 / 100);
        p.setPen(QPen(fontColor, 1));
        p.setFont(font);
        p.save();
        p.drawText(0, 0, fontRect.width(), fontRect.height(), alignMode, text);
        p.restore();
        p.end();

        watermarkImage = DImg(img);
    }

    watermarkImage.convertToDepthOfImage(&image());

    QRect watermarkRect(0, 0, watermarkImage.width(), watermarkImage.height());

    int xAdditionalValue = 0;
    int yAdditionalValue = 0;

    watermarkImage.rotate(rotationAngle);

    if (placementType == Private::SpecifiedLocation)
    {
        switch (placementPosition)
        {
            case Private::TopLeft:
            {
                watermarkRect.moveTopLeft(QPoint(marginW, marginH));
                break;
            }

            case Private::TopRight:
            {
                if ((rotationAngle == DImg::ANGLE::ROT270) || (rotationAngle == DImg::ANGLE::ROT90))
                {
                    xAdditionalValue += watermarkRect.width() - watermarkRect.height();
                }

                watermarkRect.moveTopRight(QPoint(image().width() + xAdditionalValue - 1 - marginW, marginH));
                break;
            }

            case Private::BottomLeft:
            {
                if ((rotationAngle == DImg::ANGLE::ROT90) || (rotationAngle == DImg::ANGLE::ROT270))
                {
                    yAdditionalValue += watermarkRect.height() - watermarkRect.width();
                }

                watermarkRect.moveBottomLeft(QPoint(marginW, image().height() + yAdditionalValue - 1 - marginH));
                break;
            }

            case Private::Center:
            {
                if ((rotationAngle == DImg::ANGLE::ROT90) || (rotationAngle == DImg::ANGLE::ROT270))
                {
                    xAdditionalValue += (watermarkRect.width()  - watermarkRect.height()) / 2;
                    yAdditionalValue += (watermarkRect.height() - watermarkRect.width())  / 2;
                }

                watermarkRect.moveCenter(QPoint((int)(image().width()  / 2 + xAdditionalValue),
                                                (int)(image().height() / 2 + yAdditionalValue)));
                break;
            }

            default:    // BottomRight
            {
                if ((rotationAngle == DImg::ANGLE::ROT90) || (rotationAngle == DImg::ANGLE::ROT270))
                {
                    xAdditionalValue += watermarkRect.width() - watermarkRect.height();
                    yAdditionalValue += watermarkRect.height() - watermarkRect.width();
                }

                watermarkRect.moveBottomRight(QPoint(image().width()  + xAdditionalValue - 1 - marginW,
                                                     image().height() + yAdditionalValue - 1 - marginH));
                break;
            }
        }

        image().bitBlendImage(composer,
                              &watermarkImage, 0, 0, watermarkImage.width(), watermarkImage.height(),
                              watermarkRect.left(), watermarkRect.top());
    }
    else
    {
        const float DENSE_SPACING_FACTOR  = 1.2F;
        const float SPARSE_SPACING_FACTOR = 1.8F;
        float widthRatio                  = (float)watermarkRect.width()  / image().width();
        float heightRatio                 = (float)watermarkRect.height() / image().height();
        float spacingFactor               = (denseRepetition) ? DENSE_SPACING_FACTOR : SPARSE_SPACING_FACTOR;
        spacingFactor                    *= userSparsityFactor;

        if      (placementType == Private::SystematicRepetition)
        {
            if ((rotationAngle == DImg::ANGLE::ROT270) || (rotationAngle == DImg::ANGLE::ROT90))
            {
                widthRatio  = (float)watermarkRect.height() / image().width();
                heightRatio = (float)watermarkRect.width()  / image().height();
            }

            for (uint i = 0 ; i < image().width() ; i += spacingFactor * widthRatio * image().width())
            {
                for (uint j = 0 ; j < image().height() ; j += spacingFactor * heightRatio * image().height())
                {
                    image().bitBlendImage(composer, &watermarkImage, 0, 0, watermarkImage.width(), watermarkImage.height(), i, j);
                }
            }
        }
        else if (placementType == Private::RandomRepetition)
        {
            widthRatio  = (widthRatio > heightRatio) ? widthRatio : heightRatio;
            heightRatio = widthRatio;

            qsrand(static_cast<quint64>(QTime::currentTime().msecsSinceStartOfDay()));

            for (uint i = 0 ; i < image().width() ; i += spacingFactor * widthRatio * image().width())
            {
                for (uint j = 0 ; j < image().height() ; j += spacingFactor * heightRatio * image().height())
                {
                    int number = (denseRepetition) ? 2 : 3;

                    if (qrand() % number == 0)
                    {
                        if (randomizeRotation)
                        {
                            int x = qrand() % 4;
                            watermarkImage.rotate((DImg::ANGLE)x);
                        }

                        image().bitBlendImage(composer, &watermarkImage, 0, 0, watermarkImage.width(), watermarkImage.height(), i, j);
                    }
                }
            }
        }
    }

    // TODO: Create watermark filter, move code there, implement FilterAction

    delete composer;
    image().reverseExifRotate(inputUrl().toLocalFile());

    return (savefromDImg());
}

int WaterMark::queryFontSize(const QString& text, const QFont& font, int length) const
{
    // Find font size using relative length compared to image width.

    QFont fnt = font;
    QRect fontRect;

    for (int i = 1 ; i <= 1000 ; ++i)
    {
        fnt.setPointSizeF(i);
        QFontMetrics fontMt(fnt);
        fontRect = fontMt.boundingRect(0, 0, image().width(), image().height(), 0, text);

        if (fontRect.width() > lround((image().width() * length) / 100.0))
        {
            return (i - 1);
        }
    }

    return 0;
}

} // namespace DigikamBqmWatermarkPlugin
